Change save one track to SD card to save all tracks to SD card.

This commit is contained in:
youtaol
2013-06-06 19:08:12 +08:00
commit 5ec245fcdd
996 changed files with 72341 additions and 0 deletions
@@ -0,0 +1,91 @@
/*
* 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 com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.services.TrackRecordingService;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.test.AndroidTestCase;
import java.util.List;
/**
* Tests for the BootReceiver.
*
* @author Youtao Liu
*/
public class BootReceiverTest extends AndroidTestCase {
private static final String SERVICE_NAME = "com.google.android.apps.mytracks.services.TrackRecordingService";
/**
* Tests the behavior when receive notification which is the phone boot.
*/
public void testOnReceive_startService() {
// Make sure no TrackRecordingService
Intent stopIntent = new Intent(getContext(), TrackRecordingService.class);
getContext().stopService(stopIntent);
assertFalse(isServiceExisted(getContext(), SERVICE_NAME));
BootReceiver bootReceiver = new BootReceiver();
Intent intent = new Intent();
intent.setAction(Intent.ACTION_BOOT_COMPLETED);
bootReceiver.onReceive(getContext(), intent);
// Check if the service is started
assertTrue(isServiceExisted(getContext(), SERVICE_NAME));
}
/**
* Tests the behavior when receive notification which is not the phone boot.
*/
public void testOnReceive_noStartService() {
// Make sure no TrackRecordingService
Intent stopIntent = new Intent(getContext(), TrackRecordingService.class);
getContext().stopService(stopIntent);
assertFalse(isServiceExisted(getContext(), SERVICE_NAME));
BootReceiver bootReceiver = new BootReceiver();
Intent intent = new Intent();
intent.setAction(Intent.ACTION_BUG_REPORT);
bootReceiver.onReceive(getContext(), intent);
// Check if the service is not started
assertFalse(isServiceExisted(getContext(), SERVICE_NAME));
}
/**
* Checks if a service is started in a context.
*
* @param context the context for checking a service
* @param serviceName the service name to find if existed
*/
private boolean isServiceExisted(Context context, String serviceName) {
ActivityManager activityManager = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningServiceInfo> serviceList = activityManager
.getRunningServices(Integer.MAX_VALUE);
for (int i = 0; i < serviceList.size(); i++) {
RunningServiceInfo serviceInfo = serviceList.get(i);
ComponentName componentName = serviceInfo.service;
if (componentName.getClassName().equals(serviceName)) {
return true;
}
}
return false;
}
}
@@ -0,0 +1,80 @@
/*
* Copyright 2010 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 com.google.android.apps.mytracks;
import com.google.android.maps.mytracks.R;
import android.test.AndroidTestCase;
/**
* Tests {@link ChartValueSeries}.
*
* @author Sandor Dornbush
*/
public class ChartValueSeriesTest extends AndroidTestCase {
private ChartValueSeries series;
@Override
protected void setUp() throws Exception {
series = new ChartValueSeries(getContext(),
Integer.MIN_VALUE,
Integer.MAX_VALUE,
new int[] {100, 1000 },
R.string.description_elevation_metric,
R.string.description_elevation_imperial,
R.color.chart_elevation_fill,
R.color.chart_elevation_border);
}
public void testInitialConditions() {
assertEquals(1, series.getInterval());
assertEquals(0, series.getMinMarkerValue());
assertEquals(5, series.getMaxMarkerValue());
assertTrue(series.isEnabled());
}
public void testEnabled() {
series.setEnabled(false);
assertFalse(series.isEnabled());
}
public void testSmallUpdates() {
series.update(0);
series.update(10);
series.updateDimension();
assertEquals(100, series.getInterval());
assertEquals(0, series.getMinMarkerValue());
assertEquals(500, series.getMaxMarkerValue());
}
public void testBigUpdates() {
series.update(0);
series.update(901);
series.updateDimension();
assertEquals(1000, series.getInterval());
assertEquals(0, series.getMinMarkerValue());
assertEquals(5000, series.getMaxMarkerValue());
}
public void testNotZeroBasedUpdates() {
series.update(220);
series.update(250);
series.updateDimension();
assertEquals(100, series.getInterval());
assertEquals(200, series.getMinMarkerValue());
assertEquals(700, series.getMaxMarkerValue());
}
}
@@ -0,0 +1,91 @@
/*
* 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 com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.MyTracksLocation;
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
import com.google.android.apps.mytracks.content.Track;
import android.location.Location;
/**
* Commons utilities for creating stubs of track, location. The class will be
* enriched if needs more similar stubs for test.
*
* @author Youtao Liu
*/
public class TrackStubUtils {
static final String LOCATION_PROVIDER = "gps";
public static final double INITIAL_LATITUDE = 22;
public static final double INITIAL_LONGITUDE = 22;
public static final double INITIAL_ALTITUDE = 22;
static final float INITIAL_ACCURACY = 5;
static final float INITIAL_SPEED = 10;
public static final long INITIAL_TIME = 1000L;
static final float INITIAL_BEARING = 3.0f;
// Used to change the value of latitude, longitude, and altitude.
static final double DIFFERENCE = 0.01;
/**
* Gets a a {@link Track} stub with specified number of locations.
*
* @param numberOfLocations the number of locations for the track
* @return a track stub.
*/
public static Track createTrack(int numberOfLocations) {
Track track = new Track();
for (int i = 0; i < numberOfLocations; i++) {
track.addLocation(createMyTracksLocation(INITIAL_LATITUDE + i * DIFFERENCE, INITIAL_LONGITUDE
+ i * DIFFERENCE, INITIAL_ALTITUDE + i * DIFFERENCE));
}
return track;
}
/**
* Create a MyTracks location with default values.
*
* @return a track stub.
*/
public static MyTracksLocation createMyTracksLocation() {
return createMyTracksLocation(INITIAL_LATITUDE, INITIAL_LONGITUDE, INITIAL_ALTITUDE);
}
/**
* Creates a {@link MyTracksLocation} stub with specified values.
*
* @return a MyTracksLocation stub.
*/
public static MyTracksLocation createMyTracksLocation(double latitude, double longitude,
double altitude) {
// Initial Location
Location loc = new Location(LOCATION_PROVIDER);
loc.setLatitude(latitude);
loc.setLongitude(longitude);
loc.setAltitude(altitude);
loc.setAccuracy(INITIAL_ACCURACY);
loc.setSpeed(INITIAL_SPEED);
loc.setTime(INITIAL_TIME);
loc.setBearing(INITIAL_BEARING);
SensorDataSet sd = SensorDataSet.newBuilder().build();
MyTracksLocation myTracksLocation = new MyTracksLocation(loc, sd);
return myTracksLocation;
}
}
@@ -0,0 +1,214 @@
/*
* 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 com.google.android.apps.mytracks.content;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.maps.mytracks.R;
import android.test.AndroidTestCase;
import android.util.Pair;
/**
* Tests for {@link DescriptionGeneratorImpl}.
*
* @author Jimmy Shih
*/
public class DescriptionGeneratorImplTest extends AndroidTestCase {
private static final long START_TIME = 1288721514000L;
private DescriptionGeneratorImpl descriptionGenerator;
@Override
protected void setUp() throws Exception {
descriptionGenerator = new DescriptionGeneratorImpl(getContext());
}
/**
* Tests {@link DescriptionGeneratorImpl#generateTrackDescription(Track,
* java.util.Vector, java.util.Vector, boolean)}.
*/
public void testGenerateTrackDescription() {
Track track = new Track();
TripStatistics stats = new TripStatistics();
stats.setTotalDistance(20000);
stats.setTotalTime(600000);
stats.setMovingTime(300000);
stats.setMaxSpeed(100);
stats.setMaxElevation(550);
stats.setMinElevation(-500);
stats.setTotalElevationGain(6000);
stats.setMaxGrade(0.42);
stats.setMinGrade(0.11);
stats.setStartTime(START_TIME);
track.setTripStatistics(stats);
track.setCategory("hiking");
String expected = "Created by"
+ " <a href='http://www.google.com/mobile/mytracks'>Google My Tracks</a> on Android.<p>"
+ "Name: -<br>"
+ "Activity type: hiking<br>"
+ "Description: -<br>"
+ "Total distance: 20.00 km (12.4 mi)<br>"
+ "Total time: 10:00<br>"
+ "Moving time: 05:00<br>"
+ "Average speed: 120.00 km/h (74.6 mi/h)<br>"
+ "Average moving speed: 240.00 km/h (149.1 mi/h)<br>"
+ "Max speed: 360.00 km/h (223.7 mi/h)<br>"
+ "Average pace: 0.50 min/km (0.8 min/mi)<br>"
+ "Average moving pace: 0.25 min/km (0.4 min/mi)<br>"
+ "Fastest pace: 0.17 min/km (0.3 min/mi)<br>"
+ "Max elevation: 550 m (1804 ft)<br>"
+ "Min elevation: -500 m (-1640 ft)<br>"
+ "Elevation gain: 6000 m (19685 ft)<br>"
+ "Max grade: 42 %<br>"
+ "Min grade: 11 %<br>"
+ "Recorded: " + StringUtils.formatDateTime(getContext(), START_TIME) + "<br>";
assertEquals(expected, descriptionGenerator.generateTrackDescription(track, null, null, true));
}
/**
* Tests {@link DescriptionGeneratorImpl#generateWaypointDescription(TripStatistics)}.
*/
public void testGenerateWaypointDescription() {
Waypoint waypoint = new Waypoint();
TripStatistics stats = new TripStatistics();
stats.setTotalDistance(20000);
stats.setTotalTime(600000);
stats.setMovingTime(300000);
stats.setMaxSpeed(100);
stats.setMaxElevation(550);
stats.setMinElevation(-500);
stats.setTotalElevationGain(6000);
stats.setMaxGrade(0.42);
stats.setMinGrade(0.11);
stats.setStartTime(START_TIME);
waypoint.setTripStatistics(stats);
String expected = "Total distance: 20.00 km (12.4 mi)\n"
+ "Total time: 10:00\n"
+ "Moving time: 05:00\n"
+ "Average speed: 120.00 km/h (74.6 mi/h)\n"
+ "Average moving speed: 240.00 km/h (149.1 mi/h)\n"
+ "Max speed: 360.00 km/h (223.7 mi/h)\n"
+ "Average pace: 0.50 min/km (0.8 min/mi)\n"
+ "Average moving pace: 0.25 min/km (0.4 min/mi)\n"
+ "Fastest pace: 0.17 min/km (0.3 min/mi)\n"
+ "Max elevation: 550 m (1804 ft)\n"
+ "Min elevation: -500 m (-1640 ft)\n"
+ "Elevation gain: 6000 m (19685 ft)\n"
+ "Max grade: 42 %\n"
+ "Min grade: 11 %\n"
+ "Recorded: " + StringUtils.formatDateTime(getContext(), START_TIME) + "\n";
assertEquals(
expected, descriptionGenerator.generateWaypointDescription(waypoint.getTripStatistics()));
}
/**
* Tests {@link DescriptionGeneratorImpl#writeDistance(double, StringBuilder,
* int, String)}.
*/
public void testWriteDistance() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writeDistance(1100, builder, R.string.description_total_distance, "<br>");
assertEquals("Total distance: 1.10 km (0.7 mi)<br>", builder.toString());
}
/**
* Tests {@link DescriptionGeneratorImpl#writeTime(long, StringBuilder, int,
* String)}.
*/
public void testWriteTime() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writeTime(1000, builder, R.string.description_total_time, "<br>");
assertEquals("Total time: 00:01<br>", builder.toString());
}
/**
* Tests {@link DescriptionGeneratorImpl#writeSpeed(double, StringBuilder,
* int, String)}.
*/
public void testWriteSpeed() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writeSpeed(1.1, builder, R.string.description_average_speed, "\n");
assertEquals("Average speed: 3.96 km/h (2.5 mi/h)\n", builder.toString());
}
/**
* Tests {@link DescriptionGeneratorImpl#writeElevation(double, StringBuilder,
* int, String)}.
*/
public void testWriteElevation() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writeElevation(4.2, builder, R.string.description_min_elevation, "<br>");
assertEquals("Min elevation: 4 m (14 ft)<br>", builder.toString());
}
/**
* Tests {@link DescriptionGeneratorImpl#writePace(Pair, StringBuilder, int,
* String)}.
*/
public void testWritePace() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writePace(
new Pair<Double, Double>(1.1, 2.2), builder, R.string.description_average_pace, "\n");
assertEquals("Average pace: 54.55 min/km (27.3 min/mi)\n", builder.toString());
}
/**
* Tests {@link DescriptionGeneratorImpl#writeGrade(double, StringBuilder,
* int, String)}.
*/
public void testWriteGrade() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writeGrade(.042, builder, R.string.description_max_grade, "<br>");
assertEquals("Max grade: 4 %<br>", builder.toString());
}
/**
* Tests {@link DescriptionGeneratorImpl#writeGrade(double, StringBuilder,
* int, String)} with a NaN.
*/
public void testWriteGrade_nan() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writeGrade(Double.NaN, builder, R.string.description_max_grade, "<br>");
assertEquals("Max grade: 0 %<br>", builder.toString());
}
/**
* Tests {@link DescriptionGeneratorImpl#writeGrade(double, StringBuilder,
* int, String)} with an infinite number.
*/
public void testWriteGrade_infinite() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writeGrade(
Double.POSITIVE_INFINITY, builder, R.string.description_max_grade, "<br>");
assertEquals("Max grade: 0 %<br>", builder.toString());
}
/**
* Tests {@link DescriptionGeneratorImpl#getPace(double)}.
*/
public void testGetPace() {
assertEquals(12.0, descriptionGenerator.getPace(5));
}
/**
* Tests {@link DescriptionGeneratorImpl#getPace(double)} with zero speed.
*/
public void testGetPace_zero() {
assertEquals(0.0, descriptionGenerator.getPace(0));
}
}
@@ -0,0 +1,196 @@
/*
* 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 com.google.android.apps.mytracks.content;
import com.google.android.apps.mytracks.content.MyTracksProvider.DatabaseHelper;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.test.AndroidTestCase;
/**
* A unit test for {@link MyTracksProvider}.
*
* @author Youtao Liu
*/
public class MyTracksProviderTest extends AndroidTestCase {
private SQLiteDatabase db;
private MyTracksProvider myTracksProvider;
private String DATABASE_NAME = "mytrackstest.db";
@Override
protected void setUp() throws Exception {
getContext().deleteDatabase(DATABASE_NAME);
db = (new DatabaseHelper(getContext(), DATABASE_NAME)).getWritableDatabase();
myTracksProvider = new MyTracksProvider();
super.setUp();
}
/**
* Tests the method {@link MyTracksProvider.DatabaseHelper#onCreate()}.
*/
public void testDatabaseHelper_OnCreate() {
assertTrue(checkTable(TrackPointsColumns.TABLE_NAME));
assertTrue(checkTable(TracksColumns.TABLE_NAME));
assertTrue(checkTable(WaypointsColumns.TABLE_NAME));
}
/**
* Tests the method
* {@link MyTracksProvider.DatabaseHelper#onUpgrade(SQLiteDatabase, int, int)}
* when version is less than 17.
*/
public void testDatabaseHelper_onUpgrade_Version16() {
DatabaseHelper databaseHelper = new DatabaseHelper(getContext());
dropTable(TrackPointsColumns.TABLE_NAME);
dropTable(TracksColumns.TABLE_NAME);
dropTable(WaypointsColumns.TABLE_NAME);
databaseHelper.onUpgrade(db, 16, 20);
assertTrue(checkTable(TrackPointsColumns.TABLE_NAME));
assertTrue(checkTable(TracksColumns.TABLE_NAME));
assertTrue(checkTable(WaypointsColumns.TABLE_NAME));
}
/**
* Tests the method
* {@link MyTracksProvider.DatabaseHelper#onUpgrade(SQLiteDatabase, int, int)}
* when version is 17.
*/
public void testDatabaseHelper_onUpgrade_Version17() {
DatabaseHelper databaseHelper = new DatabaseHelper(getContext());
// Make two table is only contains one normal integer column.
dropTable(TrackPointsColumns.TABLE_NAME);
dropTable(TracksColumns.TABLE_NAME);
createEmptyTable(TrackPointsColumns.TABLE_NAME);
createEmptyTable(TracksColumns.TABLE_NAME);
databaseHelper.onUpgrade(db, 17, 20);
assertTrue(isColumnExisted(TrackPointsColumns.TABLE_NAME, TrackPointsColumns.SENSOR));
assertTrue(isColumnExisted(TracksColumns.TABLE_NAME, TracksColumns.TABLEID));
assertTrue(isColumnExisted(TracksColumns.TABLE_NAME, TracksColumns.ICON));
}
/**
* Tests the method
* {@link MyTracksProvider.DatabaseHelper#onUpgrade(SQLiteDatabase, int, int)}
* when version is 18.
*/
public void testDatabaseHelper_onUpgrade_Version18() {
DatabaseHelper databaseHelper = new DatabaseHelper(getContext());
// Make two table is only contains one normal integer column.
dropTable(TrackPointsColumns.TABLE_NAME);
dropTable(TracksColumns.TABLE_NAME);
createEmptyTable(TrackPointsColumns.TABLE_NAME);
createEmptyTable(TracksColumns.TABLE_NAME);
databaseHelper.onUpgrade(db, 18, 20);
assertFalse(isColumnExisted(TrackPointsColumns.TABLE_NAME, TrackPointsColumns.SENSOR));
assertTrue(isColumnExisted(TracksColumns.TABLE_NAME, TracksColumns.TABLEID));
assertTrue(isColumnExisted(TracksColumns.TABLE_NAME, TracksColumns.ICON));
}
/**
* Tests the method
* {@link MyTracksProvider.DatabaseHelper#onUpgrade(SQLiteDatabase, int, int)}
* when version is 19.
*/
public void testDatabaseHelper_onUpgrade_Version19() {
DatabaseHelper databaseHelper = new DatabaseHelper(getContext());
// Make two table is only contains one normal integer column.
dropTable(TrackPointsColumns.TABLE_NAME);
dropTable(TracksColumns.TABLE_NAME);
createEmptyTable(TrackPointsColumns.TABLE_NAME);
createEmptyTable(TracksColumns.TABLE_NAME);
databaseHelper.onUpgrade(db, 19, 20);
assertFalse(isColumnExisted(TrackPointsColumns.TABLE_NAME, TrackPointsColumns.SENSOR));
assertFalse(isColumnExisted(TracksColumns.TABLE_NAME, TracksColumns.TABLEID));
assertTrue(isColumnExisted(TracksColumns.TABLE_NAME, TracksColumns.ICON));
}
/**
* Tests the method {@link MyTracksProvider#onCreate()}.
*/
public void testOnCreate() {
assertTrue(myTracksProvider.onCreate(getContext()));
}
/**
* Tests the method {@link MyTracksProvider#getType(Uri)}.
*/
public void testGetType() {
assertEquals(TrackPointsColumns.CONTENT_TYPE,
myTracksProvider.getType(TrackPointsColumns.CONTENT_URI));
assertEquals(TracksColumns.CONTENT_TYPE, myTracksProvider.getType(TracksColumns.CONTENT_URI));
assertEquals(WaypointsColumns.CONTENT_TYPE,
myTracksProvider.getType(WaypointsColumns.CONTENT_URI));
}
/**
* Creates an table only contains one column.
*
* @param table the name of table
*/
private void createEmptyTable(String table) {
db.execSQL("CREATE TABLE " + table + " (test INTEGER)");
}
/**
* Drops a table in database.
*
* @param table
*/
private void dropTable(String table) {
db.execSQL("Drop TABLE " + table);
}
/**
* Checks whether a table is existed.
*
* @param table the name of table
* @return true means the table has existed
*/
private boolean checkTable(String table) {
try {
db.rawQuery("select count(*) from " + table, null);
return true;
} catch (Exception e) {
return false;
}
}
/**
* Checks whether a column in a table is existed by whether can order by the
* column.
*
* @param table the name of table
* @param column the name of column
* @return true means the column has existed
*/
private boolean isColumnExisted(String table, String column) {
try {
db.execSQL("SElECT count(*) from " + table + " order by " + column);
} catch (Exception e) {
if (e.getMessage().indexOf("no such column") > -1) {
return false;
}
}
return true;
}
}
@@ -0,0 +1,908 @@
/*
* Copyright 2010 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 com.google.android.apps.mytracks.content;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationFactory;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator;
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
import com.google.android.apps.mytracks.services.TrackRecordingServiceTest.MockContext;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.testing.mocking.AndroidMock;
import com.google.android.testing.mocking.UsesMocks;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.location.Location;
import android.test.AndroidTestCase;
import android.test.RenamingDelegatingContext;
import android.test.mock.MockContentResolver;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicInteger;
/**
* A unit test for {@link MyTracksProviderUtilsImpl}.
*
* @author Bartlomiej Niechwiej
* @author Youtao Liu
*/
public class MyTracksProviderUtilsImplTest extends AndroidTestCase {
private Context context;
private MyTracksProviderUtils providerUtils;
private static final String NAME_PREFIX = "test name";
private static final String MOCK_DESC = "Mock Next Waypoint Desc!";
private static final String TEST_DESC = "Test Desc!";
private static final String TEST_DESC_NEW = "Test Desc new!";
private double INITIAL_LATITUDE = 37.0;
private double INITIAL_LONGITUDE = -57.0;
private double ALTITUDE_INTERVAL = 2.5;
@Override
protected void setUp() throws Exception {
super.setUp();
MockContentResolver mockContentResolver = new MockContentResolver();
RenamingDelegatingContext targetContext = new RenamingDelegatingContext(
getContext(), getContext(), "test.");
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);
providerUtils.deleteAllTracks();
}
public void testLocationIterator_noPoints() {
testIterator(1, 0, 1, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
}
public void testLocationIterator_customFactory() {
final Location location = new Location("test_location");
final AtomicInteger counter = new AtomicInteger();
testIterator(1, 15, 4, false, new LocationFactory() {
@Override
public Location createLocation() {
counter.incrementAndGet();
return location;
}
});
// Make sure we were called exactly as many times as we had track points.
assertEquals(15, counter.get());
}
public void testLocationIterator_nullFactory() {
try {
testIterator(1, 15, 4, false, null);
fail("Expecting IllegalArgumentException");
} catch (IllegalArgumentException e) {
// Expected.
}
}
public void testLocationIterator_noBatchAscending() {
testIterator(1, 50, 100, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
testIterator(2, 50, 50, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
}
public void testLocationIterator_noBatchDescending() {
testIterator(1, 50, 100, true, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
testIterator(2, 50, 50, true, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
}
public void testLocationIterator_batchAscending() {
testIterator(1, 50, 11, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
testIterator(2, 50, 25, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
}
public void testLocationIterator_batchDescending() {
testIterator(1, 50, 11, true, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
testIterator(2, 50, 25, true, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
}
public void testLocationIterator_largeTrack() {
testIterator(1, 20000, 2000, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
}
private List<Location> testIterator(long trackId, int numPoints, int batchSize,
boolean descending, LocationFactory locationFactory) {
long lastPointId = initializeTrack(trackId, numPoints);
((MyTracksProviderUtilsImpl) providerUtils).setDefaultCursorBatchSize(batchSize);
List<Location> locations = new ArrayList<Location>(numPoints);
LocationIterator it = providerUtils.getTrackPointLocationIterator(
trackId, -1L, descending, locationFactory);
try {
while (it.hasNext()) {
Location loc = it.next();
assertNotNull(loc);
locations.add(loc);
// Make sure the IDs are returned in the right order.
assertEquals(descending ? lastPointId - locations.size() + 1
: lastPointId - numPoints + locations.size(), it.getLocationId());
}
assertEquals(numPoints, locations.size());
} finally {
it.close();
}
return locations;
}
private long initializeTrack(long id, int numPoints) {
Track track = new Track();
track.setId(id);
track.setName("Test: " + id);
track.setNumberOfPoints(numPoints);
providerUtils.insertTrack(track);
track = providerUtils.getTrack(id);
assertNotNull(track);
Location[] locations = new Location[numPoints];
for (int i = 0; i < numPoints; ++i) {
Location loc = new Location("test");
loc.setLatitude(37.0 + (double) i / 10000.0);
loc.setLongitude(57.0 - (double) i / 10000.0);
loc.setAccuracy((float) i / 100.0f);
loc.setAltitude(i * 2.5);
locations[i] = loc;
}
providerUtils.bulkInsertTrackPoint(locations, numPoints, id);
// Load all inserted locations.
long lastPointId = -1;
int counter = 0;
LocationIterator it = providerUtils.getTrackPointLocationIterator(id, -1L, false,
MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
try {
while (it.hasNext()) {
it.next();
lastPointId = it.getLocationId();
counter++;
}
} finally {
it.close();
}
assertTrue(numPoints == 0 || lastPointId > 0);
assertEquals(numPoints, track.getNumberOfPoints());
assertEquals(numPoints, counter);
return lastPointId;
}
/**
* Tests the method {@link MyTracksProviderUtilsImpl#createTrack(Cursor)}.
*/
@UsesMocks(Cursor.class)
public void testCreateTrack() {
Cursor cursorMock = AndroidMock.createNiceMock(Cursor.class);
int startColumnIndex = 1;
int columnIndex = startColumnIndex;
AndroidMock.expect(cursorMock.getColumnIndexOrThrow(TracksColumns._ID))
.andReturn(columnIndex++);
AndroidMock.expect(cursorMock.getColumnIndexOrThrow(TracksColumns.NAME)).andReturn(
columnIndex++);
columnIndex = startColumnIndex;
// Id
AndroidMock.expect(cursorMock.isNull(columnIndex++)).andReturn(false);
// Name
AndroidMock.expect(cursorMock.isNull(columnIndex++)).andReturn(false);
long trackId = System.currentTimeMillis();
columnIndex = startColumnIndex;
// Id
AndroidMock.expect(cursorMock.getLong(columnIndex++)).andReturn(trackId);
// Name
String name = NAME_PREFIX + Long.toString(trackId);
AndroidMock.expect(cursorMock.getString(columnIndex++)).andReturn(name);
AndroidMock.replay(cursorMock);
Track track = providerUtils.createTrack(cursorMock);
assertEquals(trackId, track.getId());
assertEquals(name, track.getName());
AndroidMock.verify(cursorMock);
}
/**
* Tests the method {@link MyTracksProviderUtilsImpl#deleteAllTracks()}
*/
public void testDeleteAllTracks() {
// Insert track, points and waypoint at first.
long trackId = System.currentTimeMillis();
Track track = getTrack(trackId, 10);
insertTrackWithLocations(track);
Waypoint waypoint = new Waypoint();
providerUtils.insertWaypoint(waypoint);
ContentResolver contentResolver = context.getContentResolver();
Cursor tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null,
TracksColumns._ID);
assertEquals(1, tracksCursor.getCount());
Cursor tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI, null, null,
null, TrackPointsColumns._ID);
assertEquals(10, tracksPointsCursor.getCount());
Cursor waypointCursor = contentResolver.query(WaypointsColumns.CONTENT_URI, null, null,
null, WaypointsColumns._ID);
assertEquals(1, waypointCursor.getCount());
// Delete all.
providerUtils.deleteAllTracks();
// Check whether all have been deleted.
tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null,
TracksColumns._ID);
assertEquals(0, tracksCursor.getCount());
tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI, null, null,
null, TrackPointsColumns._ID);
assertEquals(0, tracksPointsCursor.getCount());
waypointCursor = contentResolver.query(WaypointsColumns.CONTENT_URI, null, null,
null, WaypointsColumns._ID);
assertEquals(0, waypointCursor.getCount());
}
/**
* Tests the method {@link MyTracksProviderUtilsImpl#deleteTrack(long)}.
*/
public void testDeleteTrack() {
// Insert three tracks, points of two tracks and way point of one track.
long trackId = System.currentTimeMillis();
Track track = getTrack(trackId, 10);
providerUtils.insertTrack(track);
insertTrackWithLocations(getTrack(trackId + 1, 10));
insertTrackWithLocations(getTrack(trackId + 2, 10));
Waypoint waypoint = new Waypoint();
waypoint.setTrackId(trackId);
providerUtils.insertWaypoint(waypoint);
ContentResolver contentResolver = context.getContentResolver();
Cursor tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null,
TracksColumns._ID);
assertEquals(3, tracksCursor.getCount());
Cursor tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI, null, null,
null, TrackPointsColumns._ID);
assertEquals(20, tracksPointsCursor.getCount());
Cursor waypointCursor = contentResolver.query(WaypointsColumns.CONTENT_URI, null, null,
null, WaypointsColumns._ID);
assertEquals(1, waypointCursor.getCount());
// Delete one track.
providerUtils.deleteTrack(trackId);
// Check whether all data of a track has been deleted.
tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null,
TracksColumns._ID);
assertEquals(2, tracksCursor.getCount());
tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI, null, null,
null, TrackPointsColumns._ID);
assertEquals(20, tracksPointsCursor.getCount());
waypointCursor = contentResolver.query(WaypointsColumns.CONTENT_URI, null, null,
null, WaypointsColumns._ID);
assertEquals(0, waypointCursor.getCount());
}
/**
* Tests the method {@link MyTracksProviderUtilsImpl#getAllTracks()}
*/
public void testGetAllTracks() {
int initialTrackNumber = providerUtils.getAllTracks().size();
long trackId = System.currentTimeMillis();
providerUtils.insertTrack(getTrack(trackId, 0));
List<Track> allTracks = providerUtils.getAllTracks();
assertEquals(initialTrackNumber + 1, allTracks.size());
assertEquals(trackId, allTracks.get(allTracks.size() - 1).getId());
}
/**
* Tests the method {@link MyTracksProviderUtilsImpl#getLastTrack()}
*/
public void testGetLastTrack() {
long trackId = System.currentTimeMillis();
providerUtils.insertTrack(getTrack(trackId, 0));
assertEquals(trackId, providerUtils.getLastTrack().getId());
}
/**
* Tests the method {@link MyTracksProviderUtilsImpl#getTrack(long)}
*/
public void testGetTrack() {
long trackId = System.currentTimeMillis();
providerUtils.insertTrack(getTrack(trackId, 0));
assertNotNull(providerUtils.getTrack(trackId));
}
/**
* Tests the method {@link MyTracksProviderUtilsImpl#updateTrack(Track)}
*/
public void testUpdateTrack() {
long trackId = System.currentTimeMillis();
Track track = getTrack(trackId, 0);
String nameOld = "name1";
String nameNew = "name2";
track.setName(nameOld);
providerUtils.insertTrack(track);
assertEquals(nameOld, providerUtils.getTrack(trackId).getName());
track.setName(nameNew);
providerUtils.updateTrack(track);
assertEquals(nameNew, providerUtils.getTrack(trackId).getName());
}
/**
* Tests the method {@link MyTracksProviderUtilsImpl#createContentValues(Waypoint)}.
*/
public void testCreateContentValues_waypoint() {
long trackId = System.currentTimeMillis();
Track track = getTrack(trackId, 10);
providerUtils.insertTrack(track);
// Bottom
long startTime = 1000L;
// AverageSpeed
double minGrade = -20.11;
TripStatistics statistics = new TripStatistics();
statistics.setStartTime(startTime);
statistics.setStopTime(2500L);
statistics.setTotalTime(1500L);
statistics.setMovingTime(700L);
statistics.setTotalDistance(750.0);
statistics.setTotalElevationGain(50.0);
statistics.setMaxSpeed(60.0);
statistics.setMaxElevation(1250.0);
statistics.setMinElevation(1200.0);
statistics.setMaxGrade(15.0);
statistics.setMinGrade(minGrade);
statistics.setBounds(-10000, 20000, 30000, -40000);
// Insert at first.
Waypoint waypoint = new Waypoint();
waypoint.setDescription(TEST_DESC);
waypoint.setType(WaypointType.STATISTICS);
waypoint.setTripStatistics(statistics);
Location loc = new Location("test");
loc.setLatitude(22);
loc.setLongitude(22);
loc.setAccuracy((float) 1 / 100.0f);
loc.setAltitude(2.5);
waypoint.setLocation(loc);
providerUtils.insertWaypoint(waypoint);
MyTracksProviderUtilsImpl myTracksProviderUtilsImpl = new MyTracksProviderUtilsImpl(
new MockContentResolver());
long waypointId = System.currentTimeMillis();
waypoint.setId(waypointId);
ContentValues contentValues = myTracksProviderUtilsImpl.createContentValues(waypoint);
assertEquals(waypointId, contentValues.get(WaypointsColumns._ID));
assertEquals(22 * 1000000, contentValues.get(WaypointsColumns.LONGITUDE));
assertEquals(TEST_DESC, contentValues.get(WaypointsColumns.DESCRIPTION));
assertEquals(startTime, contentValues.get(WaypointsColumns.STARTTIME));
assertEquals(minGrade, contentValues.get(WaypointsColumns.MINGRADE));
}
/**
* Tests the method {@link MyTracksProviderUtilsImpl#createWaypoint(Cursor)}.
*/
@UsesMocks(Cursor.class)
public void testCreateWaypoint() {
Cursor cursorMock = AndroidMock.createNiceMock(Cursor.class);
int startColumnIndex = 1;
int columnIndex = startColumnIndex;
AndroidMock.expect(cursorMock.getColumnIndexOrThrow(WaypointsColumns._ID))
.andReturn(columnIndex++);
AndroidMock.expect(cursorMock.getColumnIndexOrThrow(WaypointsColumns.NAME)).andReturn(
columnIndex++);
AndroidMock.expect(cursorMock.getColumnIndexOrThrow(WaypointsColumns.TRACKID)).andReturn(
columnIndex++);
columnIndex = startColumnIndex;
// Id
AndroidMock.expect(cursorMock.isNull(columnIndex++)).andReturn(false);
// Name
AndroidMock.expect(cursorMock.isNull(columnIndex++)).andReturn(false);
// trackIdIndex
AndroidMock.expect(cursorMock.isNull(columnIndex++)).andReturn(false);
long id = System.currentTimeMillis();
columnIndex = startColumnIndex;
// Id
AndroidMock.expect(cursorMock.getLong(columnIndex++)).andReturn(id);
// Name
String name = NAME_PREFIX + Long.toString(id);
AndroidMock.expect(cursorMock.getString(columnIndex++)).andReturn(name);
// trackIdIndex
long trackId = 11L;
AndroidMock.expect(cursorMock.getLong(columnIndex++)).andReturn(trackId);
AndroidMock.replay(cursorMock);
Waypoint waypoint = providerUtils.createWaypoint(cursorMock);
assertEquals(id, waypoint.getId());
assertEquals(name, waypoint.getName());
assertEquals(trackId, waypoint.getTrackId());
AndroidMock.verify(cursorMock);
}
/**
* Tests the method
* {@link MyTracksProviderUtilsImpl#deleteWaypoint(long, DescriptionGenerator)}
* when there is only one waypoint in the track.
*/
public void testDeleteWaypoint_onlyOneWayPoint() {
long trackId = System.currentTimeMillis();
Track track = getTrack(trackId, 10);
providerUtils.insertTrack(track);
// Insert at first.
Waypoint waypoint1 = new Waypoint();
waypoint1.setDescription(TEST_DESC);
waypoint1.setTrackId(trackId);
waypoint1.setType(WaypointType.STATISTICS);
providerUtils.insertWaypoint(waypoint1);
// Delete
DescriptionGenerator descriptionGenerator = new DescriptionGenerator() {
@Override
public String generateWaypointDescription(TripStatistics tripStatistics) {
return MyTracksProviderUtilsImplTest.MOCK_DESC;
}
@Override
public String generateTrackDescription(Track aTrack, Vector<Double> distances,
Vector<Double> elevations, boolean html) {
return null;
}
};
providerUtils.deleteWaypoint(1, descriptionGenerator);
assertNull(providerUtils.getWaypoint(1));
}
/**
* Tests the method
* {@link MyTracksProviderUtilsImpl#deleteWaypoint(long, DescriptionGenerator)}
* when there is more than one waypoint in the track.
*/
public void testDeleteWaypoint_hasNextWayPoint() {
long trackId = System.currentTimeMillis();
Track track = getTrack(trackId, 10);
providerUtils.insertTrack(track);
TripStatistics statistics = new TripStatistics();
statistics.setStartTime(1000L);
statistics.setStopTime(2500L);
statistics.setTotalTime(1500L);
statistics.setMovingTime(700L);
statistics.setTotalDistance(750.0);
statistics.setTotalElevationGain(50.0);
statistics.setMaxSpeed(60.0);
statistics.setMaxElevation(1250.0);
statistics.setMinElevation(1200.0);
statistics.setMaxGrade(15.0);
statistics.setMinGrade(-25.0);
statistics.setBounds(-10000, 20000, 30000, -40000);
// Insert at first.
Waypoint waypoint1 = new Waypoint();
waypoint1.setDescription(Long.toString(trackId));
waypoint1.setTrackId(trackId);
waypoint1.setType(WaypointType.STATISTICS);
waypoint1.setTripStatistics(statistics);
providerUtils.insertWaypoint(waypoint1);
Waypoint waypoint2 = new Waypoint();
waypoint2.setDescription(Long.toString(trackId));
waypoint2.setTrackId(trackId);
waypoint2.setType(WaypointType.STATISTICS);
waypoint2.setTripStatistics(statistics);
providerUtils.insertWaypoint(waypoint2);
// Delete
DescriptionGenerator descriptionGenerator = new DescriptionGenerator() {
@Override
public String generateWaypointDescription(TripStatistics tripStatistics) {
return MyTracksProviderUtilsImplTest.MOCK_DESC;
}
@Override
public String generateTrackDescription(Track aTrack, Vector<Double> distances,
Vector<Double> elevations, boolean html) {
return null;
}
};
providerUtils.deleteWaypoint(1, descriptionGenerator);
assertNull(providerUtils.getWaypoint(1));
assertEquals(MyTracksProviderUtilsImplTest.MOCK_DESC, providerUtils.getWaypoint(2)
.getDescription());
}
/**
* Tests the method {@link MyTracksProviderUtilsImpl#getFirstWaypointId(long)}.
*/
public void testGetFirstWaypointId() {
long trackId = System.currentTimeMillis();
Track track = getTrack(trackId, 10);
providerUtils.insertTrack(track);
Waypoint waypoint1 = new Waypoint();
waypoint1.setTrackId(trackId);
Waypoint waypoint2 = new Waypoint();
waypoint2.setTrackId(trackId);
providerUtils.insertWaypoint(waypoint1);
providerUtils.insertWaypoint(waypoint2);
assertEquals(-1L, providerUtils.getFirstWaypointId(-1));
assertEquals(1L, providerUtils.getFirstWaypointId(trackId));
}
/**
* Tests the method {@link MyTracksProviderUtilsImpl#getNextWaypointNumber(long, WaypointType)}.
*/
public void testGetNextWaypointNumber() {
long trackId = System.currentTimeMillis();
Track track = getTrack(trackId, 10);
providerUtils.insertTrack(track);
Waypoint waypoint1 = new Waypoint();
waypoint1.setType(WaypointType.STATISTICS);
waypoint1.setTrackId(trackId);
Waypoint waypoint2 = new Waypoint();
waypoint2.setType(WaypointType.WAYPOINT);
waypoint2.setTrackId(trackId);
Waypoint waypoint3 = new Waypoint();
waypoint3.setType(WaypointType.STATISTICS);
waypoint3.setTrackId(trackId);
Waypoint waypoint4 = new Waypoint();
waypoint4.setType(WaypointType.WAYPOINT);
waypoint4.setTrackId(trackId);
providerUtils.insertWaypoint(waypoint1);
providerUtils.insertWaypoint(waypoint2);
providerUtils.insertWaypoint(waypoint3);
providerUtils.insertWaypoint(waypoint4);
assertEquals(2, providerUtils.getNextWaypointNumber(trackId, WaypointType.STATISTICS));
assertEquals(3, providerUtils.getNextWaypointNumber(trackId, WaypointType.WAYPOINT));
}
/**
* Tests the method
* {@link MyTracksProviderUtils#getLastWaypoint(long, WaypointType)}.
*/
public void testGetLastStatisticsWaypoint() {
long trackId = System.currentTimeMillis();
Track track = getTrack(trackId, 10);
providerUtils.insertTrack(track);
Waypoint waypoint1 = new Waypoint();
waypoint1.setTrackId(trackId);
waypoint1.setType(WaypointType.STATISTICS);
waypoint1.setDescription("Desc1");
Waypoint waypoint2 = new Waypoint();
waypoint2.setTrackId(trackId);
waypoint2.setType(WaypointType.STATISTICS);
waypoint2.setDescription("Desc2");
Waypoint waypoint3 = new Waypoint();
waypoint3.setTrackId(trackId);
waypoint3.setType(WaypointType.WAYPOINT);
waypoint3.setDescription("Desc3");
providerUtils.insertWaypoint(waypoint1);
providerUtils.insertWaypoint(waypoint2);
providerUtils.insertWaypoint(waypoint3);
assertEquals("Desc2", providerUtils.getLastWaypoint(trackId, WaypointType.STATISTICS).getDescription());
}
/**
* Tests the method {@link MyTracksProviderUtilsImpl#insertWaypoint(Waypoint)} and
* {@link MyTracksProviderUtilsImpl#getWaypoint(long)}.
*/
public void testInsertAndGetWaypoint() {
long trackId = System.currentTimeMillis();
Track track = getTrack(trackId, 10);
providerUtils.insertTrack(track);
Waypoint waypoint = new Waypoint();
waypoint.setDescription(TEST_DESC);
waypoint.setTrackId(trackId);
providerUtils.insertWaypoint(waypoint);
assertEquals(TEST_DESC, providerUtils.getWaypoint(1).getDescription());
}
/**
* Tests the method {@link MyTracksProviderUtilsImpl#updateWaypoint(Waypoint)}.
*/
public void testUpdateWaypoint() {
long trackId = System.currentTimeMillis();
Track track = getTrack(trackId, 10);
providerUtils.insertTrack(track);
// Insert at first.
Waypoint waypoint = new Waypoint();
waypoint.setDescription(TEST_DESC);
waypoint.setTrackId(trackId);
providerUtils.insertWaypoint(waypoint);
// Update
waypoint = providerUtils.getWaypoint(1);
waypoint.setDescription(TEST_DESC_NEW);
providerUtils.updateWaypoint(waypoint);
assertEquals(TEST_DESC_NEW, providerUtils.getWaypoint(1).getDescription());
}
/**
* Tests the method {@link MyTracksProviderUtilsImpl#bulkInsertTrackPoint(Location[],
* int, long)}.
*/
public void testBulkInsertTrackPoint() {
// Insert track, point at first.
long trackId = System.currentTimeMillis();
Track track = getTrack(trackId, 10);
insertTrackWithLocations(track);
providerUtils.bulkInsertTrackPoint(track.getLocations().toArray(new Location[0]), -1, trackId);
assertEquals(20, providerUtils.getTrackPointCursor(trackId, -1L, 1000, false).getCount());
providerUtils.bulkInsertTrackPoint(track.getLocations().toArray(new Location[0]), 8, trackId);
assertEquals(28, providerUtils.getTrackPointCursor(trackId, -1L, 1000, false).getCount());
}
/**
* Tests the method {@link MyTracksProviderUtilsImpl#createTrackPoint(Cursor)}.
*/
@UsesMocks(Cursor.class)
public void testCreateTrackPoint() {
Cursor cursorMock = AndroidMock.createNiceMock(Cursor.class);
// Set index.
int index = 1;
// Id
AndroidMock.expect(cursorMock.getColumnIndex(TrackPointsColumns._ID)).andReturn(index++);
// Longitude
AndroidMock.expect(cursorMock.getColumnIndexOrThrow(TrackPointsColumns.LONGITUDE)).andReturn(
index++);
// Latitude
AndroidMock.expect(cursorMock.getColumnIndexOrThrow(TrackPointsColumns.LATITUDE)).andReturn(
index++);
// Time
AndroidMock.expect(cursorMock.getColumnIndexOrThrow(TrackPointsColumns.TIME))
.andReturn(index++);
// Speed
AndroidMock.expect(cursorMock.getColumnIndexOrThrow(TrackPointsColumns.SPEED)).andReturn(
index++);
// Sensor
AndroidMock.expect(cursorMock.getColumnIndexOrThrow(TrackPointsColumns.SENSOR)).andReturn(
index++);
// Set return value of isNull().
index = 2;
// Longitude
AndroidMock.expect(cursorMock.isNull(index++)).andReturn(false);
// Latitude
AndroidMock.expect(cursorMock.isNull(index++)).andReturn(false);
// Time
AndroidMock.expect(cursorMock.isNull(index++)).andReturn(false);
// Speed
AndroidMock.expect(cursorMock.isNull(index++)).andReturn(false);
// Sensor
AndroidMock.expect(cursorMock.isNull(index++)).andReturn(false);
// Set return value of isNull().
index = 2;
// Longitude
int longitude = 11;
AndroidMock.expect(cursorMock.getInt(index++)).andReturn(longitude * 1000000);
// Latitude.
int latitude = 22;
AndroidMock.expect(cursorMock.getInt(index++)).andReturn(latitude * 1000000);
// Time
long time = System.currentTimeMillis();
AndroidMock.expect(cursorMock.getLong(index++)).andReturn(time);
// Speed
float speed = 2.2f;
AndroidMock.expect(cursorMock.getFloat(index++)).andReturn(speed);
// Sensor
byte[] sensor = "Sensor state".getBytes();
AndroidMock.expect(cursorMock.getBlob(index++)).andReturn(sensor);
AndroidMock.replay(cursorMock);
Location location = providerUtils.createTrackPoint(cursorMock);
assertEquals((double) longitude, location.getLongitude());
assertEquals((double) latitude, location.getLatitude());
assertEquals(time, location.getTime());
assertEquals(speed, location.getSpeed());
AndroidMock.verify(cursorMock);
}
/**
* Tests the method
* {@link MyTracksProviderUtilsImpl#insertTrackPoint(Location, long)}.
*/
public void testInsertTrackPoint() {
// Insert track, point at first.
long trackId = System.currentTimeMillis();
Track track = getTrack(trackId, 10);
insertTrackWithLocations(track);
providerUtils.insertTrackPoint(createLocation(22), trackId);
assertEquals(11, providerUtils.getTrackPointCursor(trackId, -1L, 1000, false).getCount());
}
/**
* Tests the method {@link MyTracksProviderUtilsImpl#getFirstTrackPointId(long)}.
*/
public void testGetFirstTrackPointId() {
// Insert track, point at first.
long trackId = System.currentTimeMillis();
Track track = getTrack(trackId, 10);
insertTrackWithLocations(track);
assertEquals(1, providerUtils.getFirstTrackPointId(trackId));
}
/**
* Tests the method {@link MyTracksProviderUtilsImpl#getLastTrackPointId(long)}.
*/
public void testGetLastTrackPointId() {
// Insert track, point at first.
long trackId = System.currentTimeMillis();
Track track = getTrack(trackId, 10);
insertTrackWithLocations(track);
assertEquals(10, providerUtils.getLastTrackPointId(trackId));
}
/**
* Tests the method {@link MyTracksProviderUtilsImpl#getLastValidTrackPoint(long)}.
*/
public void testGetLastValidTrackPoint() {
// Insert track, points at first.
long trackId = System.currentTimeMillis();
Track track = getTrack(trackId, 10);
insertTrackWithLocations(track);
Location lastLocation = providerUtils.getLastValidTrackPoint(trackId);
checkLocation(9, lastLocation);
}
/**
* Tests the method
* {@link MyTracksProviderUtilsImpl#getTrackPointCursor(long, long, int, boolean)}
* in descending.
*/
public void testGetTrackPointCursor_desc() {
// Insert track, points at first.
long trackId = System.currentTimeMillis();
Track track = getTrack(trackId, 10);
insertTrackWithLocations(track);
Cursor cursor = providerUtils.getTrackPointCursor(trackId, 2L, 5, true);
assertEquals(2, cursor.getCount());
}
/**
* Tests the method
* {@link MyTracksProviderUtilsImpl#getTrackPointCursor(long, long, int, boolean)}
* in ascending.
*/
public void testGetTrackPointCursor_asc() {
// Insert track, points at first.
long trackId = System.currentTimeMillis();
Track track = getTrack(trackId, 10);
insertTrackWithLocations(track);
Cursor cursor = providerUtils.getTrackPointCursor(trackId, 2L, 5, false);
assertEquals(5, cursor.getCount());
}
/**
* Tests the method
* {@link MyTracksProviderUtilsImpl#getTrackPointLocationIterator(long, long, boolean, LocationFactory)}
* in descending.
*/
public void testGetTrackPointLocationIterator_desc() {
// Insert track, points at first.
long trackId = System.currentTimeMillis();
Track track = getTrack(trackId, 10);
insertTrackWithLocations(track);
long startTrackPointId = 2L;
LocationIterator locationIterator = providerUtils.getTrackPointLocationIterator(trackId,
startTrackPointId, true, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
for (int i = 1; i >= 0; i--) {
assertTrue(locationIterator.hasNext());
Location location = locationIterator.next();
assertEquals(2 + (i - 1), locationIterator.getLocationId());
checkLocation(i, location);
}
assertFalse(locationIterator.hasNext());
}
/**
* Tests the method
* {@link MyTracksProviderUtilsImpl#getTrackPointLocationIterator(long, long, boolean, LocationFactory)}
* in ascending.
*/
public void testGetTrackPointLocationIterator_asc() {
// Insert track, point at first.
long trackId = System.currentTimeMillis();
Track track = getTrack(trackId, 10);
insertTrackWithLocations(track);
long startTrackPointId = 2L;
LocationIterator locationIterator = providerUtils.getTrackPointLocationIterator(trackId,
startTrackPointId, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
for (int i = 1; i < 10; i++) {
assertTrue(locationIterator.hasNext());
Location location = locationIterator.next();
assertEquals(2 + (i - 1), locationIterator.getLocationId());
checkLocation(i, location);
}
assertFalse(locationIterator.hasNext());
}
/**
* Simulates a track which is used for testing.
*
* @param id the id of the track
* @param numPoints the location number in the track
* @return the simulated track
*/
private Track getTrack(long id,int numPoints) {
Track track = new Track();
track.setId(id);
track.setName("Test: " + id);
track.setNumberOfPoints(numPoints);
for(int i = 0; i < numPoints; i++) {
track.addLocation(createLocation(i));
}
return track;
}
/**
* Creates a location.
* @param i the index to set the value of location.
* @return created location
*/
private Location createLocation(int i) {
Location loc = new Location("test");
loc.setLatitude(INITIAL_LATITUDE + (double) i / 10000.0);
loc.setLongitude(INITIAL_LONGITUDE - (double) i / 10000.0);
loc.setAccuracy((float) i / 100.0f);
loc.setAltitude(i * ALTITUDE_INTERVAL);
return loc;
}
/**
* Checks the value of a location.
*
* @param i the index of this location which created in the method
* {@link MyTracksProviderUtilsImplTest#getTrack(long, int)}
* @param location the location to be checked
*/
private void checkLocation(int i, Location location) {
assertEquals(INITIAL_LATITUDE + (double) i / 10000.0, location.getLatitude());
assertEquals(INITIAL_LONGITUDE - (double) i / 10000.0, location.getLongitude());
assertEquals((float) i / 100.0f, location.getAccuracy());
assertEquals(i * ALTITUDE_INTERVAL, location.getAltitude());
}
/**
* Inserts a track with locations into the database.
*
* @param track track to be inserted
*/
private void insertTrackWithLocations(Track track) {
providerUtils.insertTrack(track);
providerUtils.bulkInsertTrackPoint(track.getLocations().toArray(new Location[0]), track
.getLocations().size(), track.getId());
}
}
@@ -0,0 +1,326 @@
/*
* 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 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.getTripStatistics();
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<ScoredResult> results = new ArrayList<ScoredResult>(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<ScoredResult> results = new ArrayList<ScoredResult>(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<ScoredResult> results = new ArrayList<ScoredResult>(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<ScoredResult> results = new ArrayList<ScoredResult>(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<ScoredResult> results = new ArrayList<ScoredResult>(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<ScoredResult> results = new ArrayList<ScoredResult>(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<ScoredResult> results = new ArrayList<ScoredResult>(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<ScoredResult> results = new ArrayList<ScoredResult>(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<ScoredResult> results = new ArrayList<ScoredResult>(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<ScoredResult> 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<ScoredResult> 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());
}
}
}
@@ -0,0 +1,792 @@
/*
* Copyright 2011 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 com.google.android.apps.mytracks.content;
import static com.google.android.testing.mocking.AndroidMock.capture;
import static com.google.android.testing.mocking.AndroidMock.eq;
import static com.google.android.testing.mocking.AndroidMock.expect;
import static com.google.android.testing.mocking.AndroidMock.isA;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.TrackStubUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationFactory;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator;
import com.google.android.apps.mytracks.services.TrackRecordingServiceTest.MockContext;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
import com.google.android.testing.mocking.AndroidMock;
import com.google.android.testing.mocking.UsesMocks;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.database.ContentObserver;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.location.Location;
import android.provider.BaseColumns;
import android.test.AndroidTestCase;
import android.test.RenamingDelegatingContext;
import android.test.mock.MockContentResolver;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;
import org.easymock.Capture;
import org.easymock.IAnswer;
/**
* Tests for {@link TrackDataHub}.
*
* @author Rodrigo Damazio
*/
public class TrackDataHubTest extends AndroidTestCase {
private static final long TRACK_ID = 42L;
private static final int TARGET_POINTS = 50;
private MockContext context;
private SharedPreferences sharedPreferences;
private MyTracksProviderUtils myTracksProviderUtils;
private DataSource dataSource;
private TrackDataManager trackDataManager;
private TrackDataHub trackDataHub;
private TrackDataListener trackDataListener1;
private TrackDataListener trackDataListener2;
private Capture<OnSharedPreferenceChangeListener> preferenceChangeListenerCapture = new Capture<
SharedPreferences.OnSharedPreferenceChangeListener>();
@UsesMocks({ MyTracksProviderUtils.class, DataSource.class, TrackDataListener.class })
@Override
protected void setUp() throws Exception {
super.setUp();
context = new MockContext(new MockContentResolver(), new RenamingDelegatingContext(
getContext(), getContext(), "test."));
sharedPreferences = context.getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
myTracksProviderUtils = AndroidMock.createMock(MyTracksProviderUtils.class);
dataSource = AndroidMock.createMock(DataSource.class, context);
trackDataManager = new TrackDataManager();
trackDataHub = new TrackDataHub(
context, trackDataManager, myTracksProviderUtils, TARGET_POINTS) {
@Override
protected DataSource newDataSource() {
return dataSource;
}
@Override
protected void runInHanderThread(Runnable runnable) {
// Run everything in the same thread
runnable.run();
}
};
trackDataListener1 = AndroidMock.createStrictMock(
"trackDataListener1", TrackDataListener.class);
trackDataListener2 = AndroidMock.createStrictMock(
"trackDataListener2", TrackDataListener.class);
PreferencesUtils.setLong(context, R.string.recording_track_id_key, TRACK_ID);
}
@Override
protected void tearDown() throws Exception {
AndroidMock.reset(dataSource);
// Expect everything to be unregistered.
dataSource.unregisterContentObserver(isA(ContentObserver.class));
AndroidMock.expectLastCall().times(3);
dataSource.unregisterOnSharedPreferenceChangeListener(
isA(OnSharedPreferenceChangeListener.class));
AndroidMock.replay(dataSource);
trackDataHub.stop();
trackDataHub = null;
super.tearDown();
}
/**
* Tests registering for tracks table update.
*/
public void testTracksTableUpdate() {
// Register two listeners
Capture<ContentObserver> contentObserverCapture = new Capture<ContentObserver>();
Track track = new Track();
expect(myTracksProviderUtils.getTrack(TRACK_ID)).andStubReturn(track);
dataSource.registerContentObserver(
eq(TracksColumns.CONTENT_URI), capture(contentObserverCapture));
trackDataListener1.onTrackUpdated(track);
trackDataListener2.onTrackUpdated(track);
replay();
trackDataHub.start();
trackDataHub.loadTrack(TRACK_ID);
trackDataHub.registerTrackDataListener(
trackDataListener1, EnumSet.of(TrackDataType.TRACKS_TABLE));
trackDataHub.registerTrackDataListener(
trackDataListener2, EnumSet.of(TrackDataType.TRACKS_TABLE));
verifyAndReset();
// Causes tracks table update
ContentObserver contentObserver = contentObserverCapture.getValue();
expect(myTracksProviderUtils.getTrack(TRACK_ID)).andStubReturn(track);
trackDataListener1.onTrackUpdated(track);
trackDataListener2.onTrackUpdated(track);
replay();
contentObserver.onChange(false);
verifyAndReset();
// Unregister one listener
expect(myTracksProviderUtils.getTrack(TRACK_ID)).andStubReturn(track);
trackDataListener2.onTrackUpdated(track);
replay();
trackDataHub.unregisterTrackDataListener(trackDataListener1);
contentObserver.onChange(false);
verifyAndReset();
// Unregister the second listener
dataSource.unregisterContentObserver(contentObserver);
replay();
trackDataHub.unregisterTrackDataListener(trackDataListener2);
contentObserver.onChange(false);
verifyAndReset();
}
/**
* Tests registering for waypoints table update.
*/
public void testWaypointsTableUpdate() {
Waypoint waypoint1 = new Waypoint();
Waypoint waypoint2 = new Waypoint();
Waypoint waypoint3 = new Waypoint();
Waypoint waypoint4 = new Waypoint();
Location location = new Location("gps");
location.setLatitude(10.0);
location.setLongitude(8.0);
waypoint1.setLocation(location);
waypoint2.setLocation(location);
waypoint3.setLocation(location);
waypoint4.setLocation(location);
// Register two listeners
Capture<ContentObserver> contentObserverCapture = new Capture<ContentObserver>();
expect(myTracksProviderUtils.getWaypointCursor(
eq(TRACK_ID), AndroidMock.leq(-1L), eq(Constants.MAX_DISPLAYED_WAYPOINTS_POINTS)))
.andStubAnswer(new FixedSizeCursorAnswer(2));
expect(myTracksProviderUtils.createWaypoint(isA(Cursor.class)))
.andReturn(waypoint1).andReturn(waypoint2).andReturn(waypoint1).andReturn(waypoint2);
dataSource.registerContentObserver(
eq(WaypointsColumns.CONTENT_URI), capture(contentObserverCapture));
trackDataListener1.clearWaypoints();
trackDataListener2.clearWaypoints();
trackDataListener1.onNewWaypoint(waypoint1);
trackDataListener2.onNewWaypoint(waypoint1);
trackDataListener1.onNewWaypoint(waypoint2);
trackDataListener2.onNewWaypoint(waypoint2);
trackDataListener1.onNewWaypointsDone();
trackDataListener2.onNewWaypointsDone();
replay();
trackDataHub.start();
trackDataHub.loadTrack(TRACK_ID);
trackDataHub.registerTrackDataListener(
trackDataListener1, EnumSet.of(TrackDataType.WAYPOINTS_TABLE));
trackDataHub.registerTrackDataListener(
trackDataListener2, EnumSet.of(TrackDataType.WAYPOINTS_TABLE));
verifyAndReset();
// Cause waypoints table update
ContentObserver contentObserver = contentObserverCapture.getValue();
expect(myTracksProviderUtils.getWaypointCursor(
eq(TRACK_ID), AndroidMock.leq(-1L), eq(Constants.MAX_DISPLAYED_WAYPOINTS_POINTS)))
.andStubAnswer(new FixedSizeCursorAnswer(3));
expect(myTracksProviderUtils.createWaypoint(isA(Cursor.class)))
.andReturn(waypoint1).andReturn(waypoint2).andReturn(waypoint3);
trackDataListener1.clearWaypoints();
trackDataListener2.clearWaypoints();
trackDataListener1.onNewWaypoint(waypoint1);
trackDataListener2.onNewWaypoint(waypoint1);
trackDataListener1.onNewWaypoint(waypoint2);
trackDataListener2.onNewWaypoint(waypoint2);
trackDataListener1.onNewWaypoint(waypoint3);
trackDataListener2.onNewWaypoint(waypoint3);
trackDataListener1.onNewWaypointsDone();
trackDataListener2.onNewWaypointsDone();
replay();
contentObserver.onChange(false);
verifyAndReset();
// Unregister one listener
expect(myTracksProviderUtils.getWaypointCursor(
eq(TRACK_ID), AndroidMock.leq(-1L), eq(Constants.MAX_DISPLAYED_WAYPOINTS_POINTS)))
.andStubAnswer(new FixedSizeCursorAnswer(4));
expect(myTracksProviderUtils.createWaypoint(isA(Cursor.class)))
.andReturn(waypoint1).andReturn(waypoint2).andReturn(waypoint3).andReturn(waypoint4);
trackDataListener2.clearWaypoints();
trackDataListener2.onNewWaypoint(waypoint1);
trackDataListener2.onNewWaypoint(waypoint2);
trackDataListener2.onNewWaypoint(waypoint3);
trackDataListener2.onNewWaypoint(waypoint4);
trackDataListener2.onNewWaypointsDone();
replay();
trackDataHub.unregisterTrackDataListener(trackDataListener1);
contentObserver.onChange(false);
verifyAndReset();
// Unregister the second listener
dataSource.unregisterContentObserver(contentObserver);
replay();
trackDataHub.unregisterTrackDataListener(trackDataListener2);
contentObserver.onChange(false);
verifyAndReset();
}
/**
* Tests track points table update.
*/
public void testTrackPointsTableUpdate() {
// Register one listener
Capture<ContentObserver> contentObserverCapture = new Capture<ContentObserver>();
dataSource.registerContentObserver(
eq(TrackPointsColumns.CONTENT_URI), capture(contentObserverCapture));
FixedSizeLocationIterator locationIterator = new FixedSizeLocationIterator(1, 10, 5);
expect(myTracksProviderUtils.getTrackPointLocationIterator(
eq(TRACK_ID), eq(0L), eq(false), isA(LocationFactory.class))).andReturn(locationIterator);
expect(myTracksProviderUtils.getLastTrackPointId(TRACK_ID)).andReturn(10L);
trackDataListener1.clearTrackPoints();
locationIterator.expectLocationsDelivered(trackDataListener1);
trackDataListener1.onNewTrackPointsDone();
replay();
trackDataHub.start();
trackDataHub.loadTrack(TRACK_ID);
trackDataHub.registerTrackDataListener(
trackDataListener1, EnumSet.of(TrackDataType.SAMPLED_IN_TRACK_POINTS_TABLE));
verifyAndReset();
// Register a second listener
locationIterator = new FixedSizeLocationIterator(1, 10, 5);
expect(myTracksProviderUtils.getTrackPointLocationIterator(
eq(TRACK_ID), eq(0L), eq(false), isA(LocationFactory.class))).andReturn(locationIterator);
expect(myTracksProviderUtils.getLastTrackPointId(TRACK_ID)).andReturn(10L);
trackDataListener2.clearTrackPoints();
locationIterator.expectLocationsDelivered(trackDataListener2);
trackDataListener2.onNewTrackPointsDone();
replay();
trackDataHub.registerTrackDataListener(
trackDataListener2, EnumSet.of(TrackDataType.SAMPLED_IN_TRACK_POINTS_TABLE));
verifyAndReset();
// Deliver more points - should go to both listeners without clearing
ContentObserver contentObserver = contentObserverCapture.getValue();
locationIterator = new FixedSizeLocationIterator(11, 10, 1);
expect(myTracksProviderUtils.getTrackPointLocationIterator(
eq(TRACK_ID), eq(11L), eq(false), isA(LocationFactory.class))).andReturn(locationIterator);
expect(myTracksProviderUtils.getLastTrackPointId(TRACK_ID)).andReturn(20L);
locationIterator.expectLocationsDelivered(trackDataListener1);
locationIterator.expectLocationsDelivered(trackDataListener2);
trackDataListener1.onNewTrackPointsDone();
trackDataListener2.onNewTrackPointsDone();
replay();
contentObserver.onChange(false);
verifyAndReset();
// Unregister one listener and change track
locationIterator = new FixedSizeLocationIterator(101, 10);
expect(myTracksProviderUtils.getTrackPointLocationIterator(
eq(TRACK_ID + 1), eq(0L), eq(false), isA(LocationFactory.class)))
.andReturn(locationIterator);
expect(myTracksProviderUtils.getLastTrackPointId(TRACK_ID + 1)).andReturn(110L);
trackDataListener2.clearTrackPoints();
locationIterator.expectLocationsDelivered(trackDataListener2);
trackDataListener2.onNewTrackPointsDone();
replay();
trackDataHub.unregisterTrackDataListener(trackDataListener1);
trackDataHub.loadTrack(TRACK_ID + 1);
verifyAndReset();
}
/**
* Tests track points table update with registering the same listener.
*/
public void testTrackPointsTableUpdate_reRegister() {
// Register one listener
Capture<ContentObserver> contentObserverCapture = new Capture<ContentObserver>();
dataSource.registerContentObserver(
eq(TrackPointsColumns.CONTENT_URI), capture(contentObserverCapture));
FixedSizeLocationIterator locationIterator = new FixedSizeLocationIterator(1, 10, 5);
expect(myTracksProviderUtils.getTrackPointLocationIterator(
eq(TRACK_ID), eq(0L), eq(false), isA(LocationFactory.class))).andReturn(locationIterator);
expect(myTracksProviderUtils.getLastTrackPointId(TRACK_ID)).andReturn(10L);
trackDataListener1.clearTrackPoints();
locationIterator.expectLocationsDelivered(trackDataListener1);
trackDataListener1.onNewTrackPointsDone();
replay();
trackDataHub.start();
trackDataHub.loadTrack(TRACK_ID);
trackDataHub.registerTrackDataListener(
trackDataListener1, EnumSet.of(TrackDataType.SAMPLED_IN_TRACK_POINTS_TABLE));
verifyAndReset();
// Unregister the listener
ContentObserver observer = contentObserverCapture.getValue();
dataSource.unregisterContentObserver(observer);
replay();
trackDataHub.unregisterTrackDataListener(trackDataListener1);
verifyAndReset();
// Register again
dataSource.registerContentObserver(
eq(TrackPointsColumns.CONTENT_URI), capture(contentObserverCapture));
locationIterator = new FixedSizeLocationIterator(1, 10, 5);
expect(myTracksProviderUtils.getTrackPointLocationIterator(
eq(TRACK_ID), eq(0L), eq(false), isA(LocationFactory.class))).andReturn(locationIterator);
expect(myTracksProviderUtils.getLastTrackPointId(TRACK_ID)).andReturn(10L);
trackDataListener1.clearTrackPoints();
locationIterator.expectLocationsDelivered(trackDataListener1);
trackDataListener1.onNewTrackPointsDone();
replay();
trackDataHub.registerTrackDataListener(
trackDataListener1, EnumSet.of(TrackDataType.SAMPLED_IN_TRACK_POINTS_TABLE));
verifyAndReset();
}
/**
* Tests tracks point able change. Register a listener after a track change.
*/
public void testTrackPointsTableUpdate_reRegisterAfterTrackChange() {
// Register one listener
Capture<ContentObserver> observerCapture = new Capture<ContentObserver>();
dataSource.registerContentObserver(
eq(TrackPointsColumns.CONTENT_URI), capture(observerCapture));
FixedSizeLocationIterator locationIterator = new FixedSizeLocationIterator(1, 10, 5);
expect(myTracksProviderUtils.getTrackPointLocationIterator(
eq(TRACK_ID), eq(0L), eq(false), isA(LocationFactory.class))).andReturn(locationIterator);
expect(myTracksProviderUtils.getLastTrackPointId(TRACK_ID)).andReturn(10L);
trackDataListener1.clearTrackPoints();
locationIterator.expectLocationsDelivered(trackDataListener1);
trackDataListener1.onNewTrackPointsDone();
replay();
trackDataHub.start();
trackDataHub.loadTrack(TRACK_ID);
trackDataHub.registerTrackDataListener(
trackDataListener1, EnumSet.of(TrackDataType.SAMPLED_IN_TRACK_POINTS_TABLE));
verifyAndReset();
// Unregister the listener
ContentObserver observer = observerCapture.getValue();
dataSource.unregisterContentObserver(observer);
replay();
trackDataHub.unregisterTrackDataListener(trackDataListener1);
verifyAndReset();
// Register the listener after a new track
dataSource.registerContentObserver(
eq(TrackPointsColumns.CONTENT_URI), capture(observerCapture));
locationIterator = new FixedSizeLocationIterator(1, 10);
expect(myTracksProviderUtils.getTrackPointLocationIterator(
eq(TRACK_ID + 1), eq(0L), eq(false), isA(LocationFactory.class)))
.andReturn(locationIterator);
expect(myTracksProviderUtils.getLastTrackPointId(TRACK_ID + 1)).andReturn(10L);
trackDataListener1.clearTrackPoints();
locationIterator.expectLocationsDelivered(trackDataListener1);
trackDataListener1.onNewTrackPointsDone();
replay();
trackDataHub.loadTrack(TRACK_ID + 1);
trackDataHub.registerTrackDataListener(
trackDataListener1, EnumSet.of(TrackDataType.SAMPLED_IN_TRACK_POINTS_TABLE));
verifyAndReset();
}
/**
* Tests track points table update with large track sampling.
*/
public void testTrackPointsTableUpdate_largeTrackSampling() {
Capture<ContentObserver> contentObserverCapture = new Capture<ContentObserver>();
dataSource.registerContentObserver(
eq(TrackPointsColumns.CONTENT_URI), capture(contentObserverCapture));
expect(myTracksProviderUtils.getLastTrackPointId(TRACK_ID)).andReturn(200L);
AndroidMock.expectLastCall().anyTimes();
FixedSizeLocationIterator locationIterator1 = new FixedSizeLocationIterator(
1, 200, 4, 25, 71, 120);
expect(myTracksProviderUtils.getTrackPointLocationIterator(
eq(TRACK_ID), eq(0L), eq(false), isA(LocationFactory.class))).andReturn(locationIterator1);
FixedSizeLocationIterator locationIterator2 = new FixedSizeLocationIterator(
1, 200, 4, 25, 71, 120);
expect(myTracksProviderUtils.getTrackPointLocationIterator(
eq(TRACK_ID), eq(0L), eq(false), isA(LocationFactory.class))).andReturn(locationIterator2);
trackDataListener1.clearTrackPoints();
locationIterator1.expectSampledLocationsDelivered(trackDataListener1, 4, false);
trackDataListener1.onNewTrackPointsDone();
trackDataListener2.clearTrackPoints();
locationIterator2.expectSampledLocationsDelivered(trackDataListener2, 4, true);
trackDataListener2.onNewTrackPointsDone();
replay();
trackDataHub.start();
trackDataHub.loadTrack(TRACK_ID);
trackDataHub.registerTrackDataListener(
trackDataListener1, EnumSet.of(TrackDataType.SAMPLED_IN_TRACK_POINTS_TABLE));
trackDataHub.registerTrackDataListener(trackDataListener2, EnumSet.of(
TrackDataType.SAMPLED_IN_TRACK_POINTS_TABLE, TrackDataType.SAMPLED_OUT_TRACK_POINTS_TABLE));
verifyAndReset();
}
/**
* Tests track points table update with resampling.
*/
public void testTrackPointsTableUpdate_resampling() {
Capture<ContentObserver> observerCapture = new Capture<ContentObserver>();
dataSource.registerContentObserver(
eq(TrackPointsColumns.CONTENT_URI), capture(observerCapture));
// Deliver 30 points (no sampling happens)
FixedSizeLocationIterator locationIterator = new FixedSizeLocationIterator(1, 30, 5);
expect(myTracksProviderUtils.getTrackPointLocationIterator(
eq(TRACK_ID), eq(0L), eq(false), isA(LocationFactory.class))).andReturn(locationIterator);
expect(myTracksProviderUtils.getLastTrackPointId(TRACK_ID)).andReturn(30L);
trackDataListener1.clearTrackPoints();
locationIterator.expectLocationsDelivered(trackDataListener1);
trackDataListener1.onNewTrackPointsDone();
replay();
trackDataHub.start();
trackDataHub.loadTrack(TRACK_ID);
trackDataHub.registerTrackDataListener(
trackDataListener1, EnumSet.of(TrackDataType.SAMPLED_IN_TRACK_POINTS_TABLE));
verifyAndReset();
// Now deliver 30 more (incrementally sampled)
ContentObserver observer = observerCapture.getValue();
locationIterator = new FixedSizeLocationIterator(31, 30);
expect(myTracksProviderUtils.getTrackPointLocationIterator(
eq(TRACK_ID), eq(31L), eq(false), isA(LocationFactory.class))).andReturn(locationIterator);
expect(myTracksProviderUtils.getLastTrackPointId(TRACK_ID)).andReturn(60L);
locationIterator.expectSampledLocationsDelivered(trackDataListener1, 2, false);
trackDataListener1.onNewTrackPointsDone();
replay();
observer.onChange(false);
verifyAndReset();
// Now another 30 (triggers resampling)
locationIterator = new FixedSizeLocationIterator(1, 90);
expect(myTracksProviderUtils.getTrackPointLocationIterator(
eq(TRACK_ID), eq(0L), eq(false), isA(LocationFactory.class))).andReturn(locationIterator);
expect(myTracksProviderUtils.getLastTrackPointId(TRACK_ID)).andReturn(90L);
trackDataListener1.clearTrackPoints();
locationIterator.expectSampledLocationsDelivered(trackDataListener1, 2, false);
trackDataListener1.onNewTrackPointsDone();
replay();
observer.onChange(false);
verifyAndReset();
}
/**
* Tests preferences change.
*/
public void testPreferencesChange() throws Exception {
// Register two listeners
PreferencesUtils.setBoolean(context, R.string.report_speed_key, true);
PreferencesUtils.setBoolean(context, R.string.metric_units_key, true);
PreferencesUtils.setInt(context, R.string.min_required_accuracy_key,
PreferencesUtils.MIN_REQUIRED_ACCURACY_DEFAULT);
PreferencesUtils.setInt(context, R.string.min_recording_distance_key,
PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT);
dataSource.registerOnSharedPreferenceChangeListener(capture(preferenceChangeListenerCapture));
expect(trackDataListener1.onMetricUnitsChanged(true)).andReturn(false);
expect(trackDataListener1.onReportSpeedChanged(true)).andReturn(false);
expect(trackDataListener1.onMinRequiredAccuracy(PreferencesUtils.MIN_REQUIRED_ACCURACY_DEFAULT))
.andReturn(false);
expect(trackDataListener1.onMinRecordingDistanceChanged(
PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT)).andReturn(false);
expect(trackDataListener2.onMetricUnitsChanged(true)).andReturn(false);
expect(trackDataListener2.onReportSpeedChanged(true)).andReturn(false);
expect(trackDataListener2.onMinRequiredAccuracy(PreferencesUtils.MIN_REQUIRED_ACCURACY_DEFAULT))
.andReturn(false);
expect(trackDataListener2.onMinRecordingDistanceChanged(
PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT)).andReturn(false);
replay();
trackDataHub.start();
trackDataHub.registerTrackDataListener(
trackDataListener1, EnumSet.of(TrackDataType.PREFERENCE));
trackDataHub.registerTrackDataListener(
trackDataListener2, EnumSet.of(TrackDataType.PREFERENCE));
verifyAndReset();
// Change report speed to false
expect(trackDataListener1.onReportSpeedChanged(false)).andReturn(false);
expect(trackDataListener2.onReportSpeedChanged(false)).andReturn(false);
replay();
PreferencesUtils.setBoolean(context, R.string.report_speed_key, false);
OnSharedPreferenceChangeListener listener = preferenceChangeListenerCapture.getValue();
listener.onSharedPreferenceChanged(
sharedPreferences, PreferencesUtils.getKey(context, R.string.report_speed_key));
verifyAndReset();
// Change metric units to false
expect(trackDataListener1.onMetricUnitsChanged(false)).andReturn(false);
expect(trackDataListener2.onMetricUnitsChanged(false)).andReturn(false);
replay();
PreferencesUtils.setBoolean(context, R.string.metric_units_key, false);
listener.onSharedPreferenceChanged(
sharedPreferences, PreferencesUtils.getKey(context, R.string.metric_units_key));
verifyAndReset();
}
/**
* Replays mocks.
*/
private void replay() {
AndroidMock.replay(myTracksProviderUtils, dataSource, trackDataListener1, trackDataListener2);
}
/**
* Verifies and resets mocks.
*/
private void verifyAndReset() {
AndroidMock.verify(myTracksProviderUtils, dataSource, trackDataListener1, trackDataListener2);
AndroidMock.reset(myTracksProviderUtils, dataSource, trackDataListener1, trackDataListener2);
}
/**
* Fixed size cursor answer.
*
* @author Jimmy Shih
*/
private static class FixedSizeCursorAnswer implements IAnswer<Cursor> {
private final int size;
public FixedSizeCursorAnswer(int size) {
this.size = size;
}
@Override
public Cursor answer() throws Throwable {
MatrixCursor cursor = new MatrixCursor(new String[] { BaseColumns._ID });
for (long i = 0; i < size; i++) {
cursor.addRow(new Object[] { i });
}
return cursor;
}
}
/**
* Fixed size location iterator.
*
* @author Jimmy Shih
*/
private static class FixedSizeLocationIterator implements LocationIterator {
private final long startId;
private final Location[] locations;
private final Set<Integer> splitIndexSet = new HashSet<Integer>();
private int currentIndex = -1;
public FixedSizeLocationIterator(long startId, int size) {
this(startId, size, null);
}
public FixedSizeLocationIterator(long startId, int size, int... splitIndexes) {
this.startId = startId;
this.locations = new Location[size];
for (int i = 0; i < size; i++) {
Location location = new Location("gps");
location.setLatitude(-15.0 + i / 1000.0);
location.setLongitude(37 + i / 1000.0);
location.setAltitude(i);
locations[i] = location;
}
if (splitIndexes != null) {
for (int splitIndex : splitIndexes) {
splitIndexSet.add(splitIndex);
Location splitLocation = locations[splitIndex];
splitLocation.setLatitude(100.0);
splitLocation.setLongitude(200.0);
}
}
}
public void expectLocationsDelivered(TrackDataListener listener) {
for (int i = 0; i < locations.length; i++) {
if (splitIndexSet.contains(i)) {
listener.onSegmentSplit(locations[i]);
} else {
listener.onSampledInTrackPoint(locations[i]);
}
}
}
public void expectSampledLocationsDelivered(
TrackDataListener listener, int sampleFrequency, boolean includeSampledOut) {
boolean includeNext = false;
for (int i = 0; i < locations.length; i++) {
if (splitIndexSet.contains(i)) {
listener.onSegmentSplit(locations[i]);
includeNext = true;
} else if (includeNext || (i % sampleFrequency == 0)) {
listener.onSampledInTrackPoint(locations[i]);
includeNext = false;
} else if (includeSampledOut) {
listener.onSampledOutTrackPoint(locations[i]);
}
}
}
@Override
public boolean hasNext() {
return currentIndex < locations.length - 1;
}
@Override
public Location next() {
currentIndex++;
return locations[currentIndex];
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public long getLocationId() {
return startId + currentIndex;
}
@Override
public void close() {
// Do nothing
}
}
/**
* Tests the method {@link TrackDataHub#start()}.
*/
public void testRegisterTracksTableListener() {
Capture<ContentObserver> observerCapture = new Capture<ContentObserver>();
dataSource.registerContentObserver(eq(TracksColumns.CONTENT_URI), capture(observerCapture));
Track track = TrackStubUtils.createTrack(1);
expect(myTracksProviderUtils.getTrack(capture(new Capture<Long>()))).andReturn(track);
// Make the track id is unique.
PreferencesUtils.setLong(context, R.string.recording_track_id_key, System.currentTimeMillis());
trackDataListener1.onTrackUpdated(track);
replay();
trackDataHub.start();
trackDataHub.registerTrackDataListener(
trackDataListener1, EnumSet.of(TrackDataType.TRACKS_TABLE));
verifyAndReset();
}
/**
* Tests the method {@link TrackDataHub#start()}.
*/
public void testRegisterWaypointsTableListener() {
Capture<ContentObserver> observerCapture = new Capture<ContentObserver>();
dataSource.registerContentObserver(eq(WaypointsColumns.CONTENT_URI), capture(observerCapture));
expect(myTracksProviderUtils.getWaypointCursor(
capture(new Capture<Long>()), capture(new Capture<Long>()),
capture(new Capture<Integer>()))).andReturn(null);
trackDataListener1.clearWaypoints();
trackDataListener1.onNewWaypointsDone();
replay();
trackDataHub.start();
trackDataHub.registerTrackDataListener(
trackDataListener1, EnumSet.of(TrackDataType.WAYPOINTS_TABLE));
verifyAndReset();
}
/**
* Tests the method {@link TrackDataHub#notifyPreferenceChanged(String)} when
* the key is R.string.min_required_accuracy_key.
*/
public void testNotifyPreferenceChanged_minRequiredAccuracy() {
int value = 1;
PreferencesUtils.setInt(context, R.string.min_required_accuracy_key, value);
trackDataHub.notifyPreferenceChanged(PreferencesUtils
.getKey(context, R.string.min_required_accuracy_key));
assertEquals(value, trackDataHub.getMinRequiredAccuracy());
PreferencesUtils.setInt(context, R.string.min_required_accuracy_key, value + 1);
trackDataHub.notifyPreferenceChanged(PreferencesUtils
.getKey(context, R.string.min_required_accuracy_key));
assertEquals(value + 1, trackDataHub.getMinRequiredAccuracy());
}
/**
* Tests the method {@link TrackDataHub#notifyPreferenceChanged(String)} when
* the key is R.string.metric_units_key.
*/
public void testNotifyPreferenceChanged_metricUnitsNoNotify() {
boolean value = false;
PreferencesUtils.setBoolean(context, R.string.metric_units_key, value);
trackDataHub.notifyPreferenceChanged(PreferencesUtils
.getKey(context, R.string.metric_units_key));
assertEquals(value, trackDataHub.isMetricUnits());
PreferencesUtils.setBoolean(context, R.string.metric_units_key, !value);
trackDataHub.notifyPreferenceChanged(PreferencesUtils
.getKey(context, R.string.metric_units_key));
assertEquals(!value, trackDataHub.isMetricUnits());
}
/**
* Tests the method {@link TrackDataHub#notifyPreferenceChanged(String)} when
* the key is R.string.metric_units_key.
*/
public void testNotifyPreferenceChanged_reportSpeedNoNotify() {
boolean value = false;
PreferencesUtils.setBoolean(context, R.string.report_speed_key, value);
trackDataHub.notifyPreferenceChanged(PreferencesUtils
.getKey(context, R.string.report_speed_key));
assertEquals(value, trackDataHub.isReportSpeed());
PreferencesUtils.setBoolean(context, R.string.report_speed_key, !value);
trackDataHub.notifyPreferenceChanged(PreferencesUtils
.getKey(context, R.string.report_speed_key));
assertEquals(!value, trackDataHub.isReportSpeed());
}
}
@@ -0,0 +1,58 @@
/*
* Copyright 2010 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 com.google.android.apps.mytracks.content;
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
import android.os.Parcel;
import android.test.AndroidTestCase;
/**
* Tests for the WaypointCreationRequest class.
* {@link WaypointCreationRequest}
*
* @author Sandor Dornbush
*/
public class WaypointCreationRequestTest extends AndroidTestCase {
public void testTypeParceling() {
WaypointCreationRequest original = WaypointCreationRequest.DEFAULT_WAYPOINT;
Parcel p = Parcel.obtain();
original.writeToParcel(p, 0);
p.setDataPosition(0);
WaypointCreationRequest copy = WaypointCreationRequest.CREATOR.createFromParcel(p);
assertEquals(original.getType(), copy.getType());
assertFalse(copy.isTrackStatistics());
assertNull(copy.getName());
assertNull(copy.getDescription());
assertNull(copy.getIconUrl());
}
public void testAllAttributesParceling() {
WaypointCreationRequest original = new WaypointCreationRequest(
WaypointType.WAYPOINT, false, "name", "category", "description", "img.png");
Parcel p = Parcel.obtain();
original.writeToParcel(p, 0);
p.setDataPosition(0);
WaypointCreationRequest copy = WaypointCreationRequest.CREATOR.createFromParcel(p);
assertEquals(original.getType(), copy.getType());
assertFalse(copy.isTrackStatistics());
assertEquals("name", copy.getName());
assertEquals("category", copy.getCategory());
assertEquals("description", copy.getDescription());
assertEquals("img.png", copy.getIconUrl());
}
}
@@ -0,0 +1,365 @@
/*
* 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 com.google.android.apps.mytracks.fragments;
import com.google.android.apps.mytracks.ChartView;
import com.google.android.apps.mytracks.TrackStubUtils;
import com.google.android.apps.mytracks.content.MyTracksLocation;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
import com.google.android.apps.mytracks.util.UnitConversions;
import android.location.Location;
import android.test.AndroidTestCase;
/**
* Tests {@link ChartFragment}.
*
* @author Youtao Liu
*/
public class ChartFragmentTest extends AndroidTestCase {
private ChartFragment chartFragment;
private final double HOURS_PER_UNIT = 60.0;
@Override
protected void setUp() throws Exception {
chartFragment = new ChartFragment();
chartFragment.setChartView(new ChartView(getContext()));
chartFragment.setTripStatisticsUpdater(TrackStubUtils.INITIAL_TIME);
}
/**
* Tests the logic to get the incorrect values of sensor in
* {@link ChartFragment#fillDataPoint(Location, double[])}
*/
public void testFillDataPoint_sensorIncorrect() {
MyTracksLocation myTracksLocation = TrackStubUtils.createMyTracksLocation();
// No input.
double[] point = fillDataPointTestHelper(myTracksLocation);
assertEquals(Double.NaN, point[ChartView.HEART_RATE_SERIES + 1]);
assertEquals(Double.NaN, point[ChartView.CADENCE_SERIES + 1]);
assertEquals(Double.NaN, point[ChartView.POWER_SERIES + 1]);
// Input incorrect state.
// Creates SensorData.
Sensor.SensorData.Builder heartRateData = Sensor.SensorData.newBuilder()
.setValue(100).setState(Sensor.SensorState.NONE);
Sensor.SensorData.Builder cadenceData = Sensor.SensorData.newBuilder()
.setValue(101).setState(Sensor.SensorState.NONE);
Sensor.SensorData.Builder powerData = Sensor.SensorData.newBuilder()
.setValue(102).setState(Sensor.SensorState.NONE);
// Creates SensorDataSet.
SensorDataSet sensorDataSet = myTracksLocation.getSensorDataSet();
sensorDataSet = sensorDataSet.toBuilder()
.setHeartRate(heartRateData)
.setCadence(cadenceData)
.setPower(powerData)
.build();
myTracksLocation.setSensorDataSet(sensorDataSet);
// Test.
point = fillDataPointTestHelper(myTracksLocation);
assertEquals(Double.NaN, point[ChartView.HEART_RATE_SERIES + 1]);
assertEquals(Double.NaN, point[ChartView.CADENCE_SERIES + 1]);
assertEquals(Double.NaN, point[ChartView.POWER_SERIES + 1]);
}
/**
* Tests the logic to get the correct values of sensor in
* {@link ChartFragment#fillDataPoint(Location, double[])}.
*/
public void testFillDataPoint_sensorCorrect() {
MyTracksLocation myTracksLocation = TrackStubUtils.createMyTracksLocation();
// No input.
double[] point = fillDataPointTestHelper(myTracksLocation);
assertEquals(Double.NaN, point[ChartView.HEART_RATE_SERIES + 1]);
assertEquals(Double.NaN, point[ChartView.CADENCE_SERIES + 1]);
assertEquals(Double.NaN, point[ChartView.POWER_SERIES + 1]);
// Creates SensorData.
Sensor.SensorData.Builder heartRateData = Sensor.SensorData.newBuilder()
.setValue(100).setState(Sensor.SensorState.SENDING);
Sensor.SensorData.Builder cadenceData = Sensor.SensorData.newBuilder()
.setValue(101).setState(Sensor.SensorState.SENDING);
Sensor.SensorData.Builder powerData = Sensor.SensorData.newBuilder()
.setValue(102).setState(Sensor.SensorState.SENDING);
// Creates SensorDataSet.
SensorDataSet sensorDataSet = myTracksLocation.getSensorDataSet();
sensorDataSet = sensorDataSet.toBuilder()
.setHeartRate(heartRateData)
.setCadence(cadenceData)
.setPower(powerData)
.build();
myTracksLocation.setSensorDataSet(sensorDataSet);
// Test.
point = fillDataPointTestHelper(myTracksLocation);
assertEquals(100.0, point[ChartView.HEART_RATE_SERIES + 1]);
assertEquals(101.0, point[ChartView.CADENCE_SERIES + 1]);
assertEquals(102.0, point[ChartView.POWER_SERIES + 1]);
}
/**
* Tests the logic to get the value of metric Distance in
* {@link ChartFragment#fillDataPoint(Location, double[])}.
*/
public void testFillDataPoint_distanceMetric() {
// By distance.
chartFragment.setChartByDistance(true);
// Resets last location and writes first location.
MyTracksLocation myTracksLocation1 = TrackStubUtils.createMyTracksLocation();
double[] point = fillDataPointTestHelper(myTracksLocation1);
assertEquals(0.0, point[0]);
// The second is a same location, just different time.
MyTracksLocation myTracksLocation2 = TrackStubUtils.createMyTracksLocation();
point = fillDataPointTestHelper(myTracksLocation2);
assertEquals(0.0, point[0]);
// The third location is a new location, and use metric.
MyTracksLocation myTracksLocation3 = TrackStubUtils.createMyTracksLocation();
myTracksLocation3.setLatitude(23);
point = fillDataPointTestHelper(myTracksLocation3);
// Computes the distance between Latitude 22 and 23.
float[] results = new float[4];
Location.distanceBetween(myTracksLocation2.getLatitude(), myTracksLocation2.getLongitude(),
myTracksLocation3.getLatitude(), myTracksLocation3.getLongitude(), results);
double distance1 = results[0] * UnitConversions.M_TO_KM;
assertEquals(distance1, point[0]);
// The fourth location is a new location, and use metric.
MyTracksLocation myTracksLocation4 = TrackStubUtils.createMyTracksLocation();
myTracksLocation4.setLatitude(24);
point = fillDataPointTestHelper(myTracksLocation4);
// Computes the distance between Latitude 23 and 24.
Location.distanceBetween(myTracksLocation3.getLatitude(), myTracksLocation3.getLongitude(),
myTracksLocation4.getLatitude(), myTracksLocation4.getLongitude(), results);
double distance2 = results[0] * UnitConversions.M_TO_KM;
assertEquals((distance1 + distance2), point[0]);
}
/**
* Tests the logic to get the value of imperial Distance in
* {@link ChartFragment#fillDataPoint(Location, double[])}.
*/
public void testFillDataPoint_distanceImperial() {
// By distance.
chartFragment.setChartByDistance(true);
// Setups to use imperial.
chartFragment.setMetricUnits(false);
// The first is a same location, just different time.
MyTracksLocation myTracksLocation1 = TrackStubUtils.createMyTracksLocation();
double[] point = fillDataPointTestHelper(myTracksLocation1);
assertEquals(0.0, point[0]);
// The second location is a new location, and use imperial.
MyTracksLocation myTracksLocation2 = TrackStubUtils.createMyTracksLocation();
myTracksLocation2.setLatitude(23);
point = fillDataPointTestHelper(myTracksLocation2);
/*
* Computes the distance between Latitude 22 and 23. And for we set using
* imperial, the distance should be multiplied by UnitConversions.KM_TO_MI.
*/
float[] results = new float[4];
Location.distanceBetween(myTracksLocation1.getLatitude(), myTracksLocation1.getLongitude(),
myTracksLocation2.getLatitude(), myTracksLocation2.getLongitude(), results);
double distance1 = results[0] * UnitConversions.M_TO_KM * UnitConversions.KM_TO_MI;
assertEquals(distance1, point[0]);
// The third location is a new location, and use imperial.
MyTracksLocation myTracksLocation3 = TrackStubUtils.createMyTracksLocation();
myTracksLocation3.setLatitude(24);
point = fillDataPointTestHelper(myTracksLocation3);
/*
* Computes the distance between Latitude 23 and 24. And for we set using
* imperial, the distance should be multiplied by UnitConversions.KM_TO_MI.
*/
Location.distanceBetween(myTracksLocation2.getLatitude(), myTracksLocation2.getLongitude(),
myTracksLocation3.getLatitude(), myTracksLocation3.getLongitude(), results);
double distance2 = results[0] * UnitConversions.M_TO_KM * UnitConversions.KM_TO_MI;
assertEquals(distance1 + distance2, point[0]);
}
/**
* Tests the logic to get the values of time in
* {@link ChartFragment#fillDataPoint(Location, double[])}.
*/
public void testFillDataPoint_time() {
// By time
chartFragment.setChartByDistance(false);
MyTracksLocation myTracksLocation1 = TrackStubUtils.createMyTracksLocation();
double[] point = fillDataPointTestHelper(myTracksLocation1);
assertEquals(0.0, point[0]);
long timeSpan = 222;
MyTracksLocation myTracksLocation2 = TrackStubUtils.createMyTracksLocation();
myTracksLocation2.setTime(myTracksLocation1.getTime() + timeSpan);
point = fillDataPointTestHelper(myTracksLocation2);
assertEquals((double) timeSpan, point[0]);
}
/**
* Tests the logic to get the value of elevation in
* {@link ChartFragment#fillDataPoint(Location, double[])} by one and two
* points.
*/
public void testFillDataPoint_elevation() {
MyTracksLocation myTracksLocation1 = TrackStubUtils.createMyTracksLocation();
/*
* At first, clear old points of elevation, so give true to the second
* parameter. Then only one value INITIALLONGTITUDE in buffer.
*/
double[] point = fillDataPointTestHelper(myTracksLocation1);
assertEquals(TrackStubUtils.INITIAL_ALTITUDE, point[ChartView.ELEVATION_SERIES + 1]);
/*
* Send another value to buffer, now there are two values, INITIALALTITUDE
* and INITIALALTITUDE * 2.
*/
MyTracksLocation myTracksLocation2 = TrackStubUtils.createMyTracksLocation();
myTracksLocation2.setAltitude(TrackStubUtils.INITIAL_ALTITUDE * 2);
point = fillDataPointTestHelper(myTracksLocation2);
assertEquals((TrackStubUtils.INITIAL_ALTITUDE + TrackStubUtils.INITIAL_ALTITUDE * 2) / 2.0,
point[ChartView.ELEVATION_SERIES + 1]);
}
/**
* Tests the logic to get the value of speed in
* {@link ChartFragment#fillDataPoint(Location, double[])}. In this test,
* firstly remove all points in memory, and then fill in two points one by
* one. The speed values of these points are 129, 130.
*/
public void testFillDataPoint_speed() {
/*
* At first, clear old points of speed, so give true to the second
* parameter. It will not be filled in to the speed buffer.
*/
MyTracksLocation myTracksLocation1 = TrackStubUtils.createMyTracksLocation();
myTracksLocation1.setSpeed(128.5f);
double[] point = fillDataPointTestHelper(myTracksLocation1);
assertEquals(0.0, point[ChartView.SPEED_SERIES + 1]);
/*
* Tests the logic when both metricUnits and reportSpeed are true.This
* location will be filled into speed buffer.
*/
MyTracksLocation myTracksLocation2 = TrackStubUtils.createMyTracksLocation();
/*
* Add a time span here to make sure the second point is valid, the value
* 222 here is doesn't matter.
*/
myTracksLocation2.setTime(myTracksLocation1.getTime() + 222);
myTracksLocation2.setSpeed(130);
point = fillDataPointTestHelper(myTracksLocation2);
assertEquals(130.0 * UnitConversions.MS_TO_KMH, point[ChartView.SPEED_SERIES + 1]);
}
/**
* Tests the logic to compute speed when use Imperial.
*/
public void testFillDataPoint_speedImperial() {
// Setups to use imperial.
chartFragment.setMetricUnits(false);
// First data point is not added to the speed buffer
MyTracksLocation myTracksLocation1 = TrackStubUtils.createMyTracksLocation();
myTracksLocation1.setSpeed(100.0f);
double[] point = fillDataPointTestHelper(myTracksLocation1);
assertEquals(0.0, point[ChartView.SPEED_SERIES + 1]);
MyTracksLocation myTracksLocation2 = TrackStubUtils.createMyTracksLocation();
/*
* Add a time span here to make sure the second point is valid and the speed is valid.
*
* Speed is valid if:
* speedDifference > Constants.MAX_ACCELERATION * timeDifference
* speedDifference = 102 -100
* timeDifference = 222
*/
myTracksLocation2.setTime(myTracksLocation2.getTime() + 222);
myTracksLocation2.setSpeed(102);
point = fillDataPointTestHelper(myTracksLocation2);
assertEquals(102.0 * UnitConversions.MS_TO_KMH * UnitConversions.KM_TO_MI,
point[ChartView.SPEED_SERIES + 1]);
}
/**
* Tests the logic to get pace value when reportSpeed is false.
*/
public void testFillDataPoint_pace_nonZeroSpeed() {
// Setups reportSpeed to false.
chartFragment.setReportSpeed(false);
// First data point is not added to the speed buffer
MyTracksLocation myTracksLocation1 = TrackStubUtils.createMyTracksLocation();
myTracksLocation1.setSpeed(100.0f);
double[] point = fillDataPointTestHelper(myTracksLocation1);
assertEquals(0.0, point[ChartView.SPEED_SERIES + 1]);
MyTracksLocation myTracksLocation2 = TrackStubUtils.createMyTracksLocation();
/*
* Add a time span here to make sure the second point is valid and the speed is valid.
*
* Speed is valid if:
* speedDifference > Constants.MAX_ACCELERATION * timeDifference
* speedDifference = 102 -100
* timeDifference = 222
*/
myTracksLocation2.setTime(myTracksLocation2.getTime() + 222);
myTracksLocation2.setSpeed(102);
point = fillDataPointTestHelper(myTracksLocation2);
assertEquals(
HOURS_PER_UNIT / (102.0 * UnitConversions.MS_TO_KMH), point[ChartView.PACE_SERIES + 1]);
}
/**
* Tests the logic to get pace value when reportSpeed is false and average
* speed is zero.
*/
public void testFillDataPoint_pace_zeroSpeed() {
// Setups reportSpeed to false.
chartFragment.setReportSpeed(false);
MyTracksLocation myTracksLocation = TrackStubUtils.createMyTracksLocation();
myTracksLocation.setSpeed(0);
double[] point = fillDataPointTestHelper(myTracksLocation);
assertEquals(0.0, point[ChartView.PACE_SERIES + 1]);
}
/**
* Helper method to test fillDataPoint.
*
* @param location location to fill
* @return data of this location
*/
private double[] fillDataPointTestHelper(Location location) {
double[] point = new double[ChartView.NUM_SERIES + 1];
chartFragment.fillDataPoint(location, point);
return point;
}
}
@@ -0,0 +1,267 @@
/*
* Copyright 2010 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 com.google.android.apps.mytracks.io.backup;
import com.google.android.apps.mytracks.content.ContentTypeIds;
import android.database.MatrixCursor;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import junit.framework.TestCase;
/**
* Tests for {@link DatabaseDumper}.
*
* @author Rodrigo Damazio
*/
public class DatabaseDumperTest extends TestCase {
/**
* This class is the same as {@link MatrixCursor}, except this class
* implements {@link #getBlob} ({@link MatrixCursor} leaves it
* unimplemented).
*/
private class BlobAwareMatrixCursor extends MatrixCursor {
public BlobAwareMatrixCursor(String[] columnNames) {
super(columnNames);
}
@Override public byte[] getBlob(int columnIndex) {
return getString(columnIndex).getBytes();
}
}
private static final String[] COLUMN_NAMES = {
"intCol", "longCol", "floatCol", "doubleCol", "stringCol", "boolCol", "blobCol"
};
private static final byte[] COLUMN_TYPES = {
ContentTypeIds.INT_TYPE_ID, ContentTypeIds.LONG_TYPE_ID,
ContentTypeIds.FLOAT_TYPE_ID, ContentTypeIds.DOUBLE_TYPE_ID,
ContentTypeIds.STRING_TYPE_ID, ContentTypeIds.BOOLEAN_TYPE_ID,
ContentTypeIds.BLOB_TYPE_ID
};
private static final String[][] FAKE_DATA = {
{ "42", "123456789", "3.1415", "2.72", "lolcat", "1", "blob" },
{ null, "123456789", "3.1415", "2.72", "lolcat", "1", "blob" },
{ "42", null, "3.1415", "2.72", "lolcat", "1", "blob" },
{ "42", "123456789", null, "2.72", "lolcat", "1", "blob" },
{ "42", "123456789", "3.1415", null, "lolcat", "1", "blob" },
{ "42", "123456789", "3.1415", "2.72", null, "1", "blob" },
{ "42", "123456789", "3.1415", "2.72", "lolcat", null, "blob" },
{ "42", "123456789", "3.1415", "2.72", "lolcat", "1", null },
};
private static final long[] EXPECTED_FIELD_SETS = {
0x7F, 0x7E, 0x7D, 0x7B, 0x77, 0x6F, 0x5F, 0x3F
};
private BlobAwareMatrixCursor cursor;
@Override
protected void setUp() throws Exception {
super.setUp();
// Add fake data to the cursor
cursor = new BlobAwareMatrixCursor(COLUMN_NAMES);
for (String[] row : FAKE_DATA) {
cursor.addRow(row);
}
}
public void testWriteAllRows_noNulls() throws Exception {
testWriteAllRows(false);
}
public void testWriteAllRows_withNulls() throws Exception {
testWriteAllRows(true);
}
private void testWriteAllRows(boolean hasNullFields) throws Exception {
// Dump it
DatabaseDumper dumper = new DatabaseDumper(COLUMN_NAMES, COLUMN_TYPES, hasNullFields);
ByteArrayOutputStream outStream = new ByteArrayOutputStream(1024);
DataOutputStream writer = new DataOutputStream(outStream );
dumper.writeAllRows(cursor, writer);
// Read the results
byte[] result = outStream.toByteArray();
ByteArrayInputStream inputStream = new ByteArrayInputStream(result);
DataInputStream reader = new DataInputStream(inputStream);
// Verify the header
assertHeader(reader);
// Verify the number of rows
assertEquals(FAKE_DATA.length, reader.readInt());
// Row 0 -- everything populated
assertEquals(EXPECTED_FIELD_SETS[0], reader.readLong());
assertEquals(42, reader.readInt());
assertEquals(123456789L, reader.readLong());
assertEquals(3.1415f, reader.readFloat());
assertEquals(2.72, reader.readDouble());
assertEquals("lolcat", reader.readUTF());
assertTrue(reader.readBoolean());
assertEquals(4, reader.readInt());
assertEquals("blob", readBlob(reader, 4));
// Row 1 -- no int
assertEquals(EXPECTED_FIELD_SETS[1], reader.readLong());
if (hasNullFields) reader.readInt();
assertEquals(123456789L, reader.readLong());
assertEquals(3.1415f, reader.readFloat());
assertEquals(2.72, reader.readDouble());
assertEquals("lolcat", reader.readUTF());
assertTrue(reader.readBoolean());
assertEquals(4, reader.readInt());
assertEquals("blob", readBlob(reader, 4));
// Row 2 -- no long
assertEquals(EXPECTED_FIELD_SETS[2], reader.readLong());
assertEquals(42, reader.readInt());
if (hasNullFields) reader.readLong();
assertEquals(3.1415f, reader.readFloat());
assertEquals(2.72, reader.readDouble());
assertEquals("lolcat", reader.readUTF());
assertTrue(reader.readBoolean());
assertEquals(4, reader.readInt());
assertEquals("blob", readBlob(reader, 4));
// Row 3 -- no float
assertEquals(EXPECTED_FIELD_SETS[3], reader.readLong());
assertEquals(42, reader.readInt());
assertEquals(123456789L, reader.readLong());
if (hasNullFields) reader.readFloat();
assertEquals(2.72, reader.readDouble());
assertEquals("lolcat", reader.readUTF());
assertTrue(reader.readBoolean());
assertEquals(4, reader.readInt());
assertEquals("blob", readBlob(reader, 4));
// Row 4 -- no double
assertEquals(EXPECTED_FIELD_SETS[4], reader.readLong());
assertEquals(42, reader.readInt());
assertEquals(123456789L, reader.readLong());
assertEquals(3.1415f, reader.readFloat());
if (hasNullFields) reader.readDouble();
assertEquals("lolcat", reader.readUTF());
assertTrue(reader.readBoolean());
assertEquals(4, reader.readInt());
assertEquals("blob", readBlob(reader, 4));
// Row 5 -- no string
assertEquals(EXPECTED_FIELD_SETS[5], reader.readLong());
assertEquals(42, reader.readInt());
assertEquals(123456789L, reader.readLong());
assertEquals(3.1415f, reader.readFloat());
assertEquals(2.72, reader.readDouble());
if (hasNullFields) reader.readUTF();
assertTrue(reader.readBoolean());
assertEquals(4, reader.readInt());
assertEquals("blob", readBlob(reader, 4));
// Row 6 -- no boolean
assertEquals(EXPECTED_FIELD_SETS[6], reader.readLong());
assertEquals(42, reader.readInt());
assertEquals(123456789L, reader.readLong());
assertEquals(3.1415f, reader.readFloat());
assertEquals(2.72, reader.readDouble());
assertEquals("lolcat", reader.readUTF());
if (hasNullFields) reader.readBoolean();
assertEquals(4, reader.readInt());
assertEquals("blob", readBlob(reader, 4));
// Row 7 -- no blob
assertEquals(EXPECTED_FIELD_SETS[7], reader.readLong());
assertEquals(42, reader.readInt());
assertEquals(123456789L, reader.readLong());
assertEquals(3.1415f, reader.readFloat());
assertEquals(2.72, reader.readDouble());
assertEquals("lolcat", reader.readUTF());
assertTrue(reader.readBoolean());
if (hasNullFields) {
int length = reader.readInt();
readBlob(reader, length);
}
}
public void testFewerRows() throws Exception {
// Dump only the first two rows
DatabaseDumper dumper = new DatabaseDumper(COLUMN_NAMES, COLUMN_TYPES, false);
ByteArrayOutputStream outStream = new ByteArrayOutputStream(1024);
DataOutputStream writer = new DataOutputStream(outStream);
dumper.writeHeaders(cursor, 2, writer);
cursor.moveToFirst();
dumper.writeOneRow(cursor, writer);
cursor.moveToNext();
dumper.writeOneRow(cursor, writer);
// Read the results
byte[] result = outStream.toByteArray();
ByteArrayInputStream inputStream = new ByteArrayInputStream(result);
DataInputStream reader = new DataInputStream(inputStream);
// Verify the header
assertHeader(reader);
// Verify the number of rows
assertEquals(2, reader.readInt());
// Row 0
assertEquals(EXPECTED_FIELD_SETS[0], reader.readLong());
assertEquals(42, reader.readInt());
assertEquals(123456789L, reader.readLong());
assertEquals(3.1415f, reader.readFloat());
assertEquals(2.72, reader.readDouble());
assertEquals("lolcat", reader.readUTF());
assertTrue(reader.readBoolean());
assertEquals(4, reader.readInt());
assertEquals("blob", readBlob(reader, 4));
// Row 1
assertEquals(EXPECTED_FIELD_SETS[1], reader.readLong());
// Null field not read
assertEquals(123456789L, reader.readLong());
assertEquals(3.1415f, reader.readFloat());
assertEquals(2.72, reader.readDouble());
assertEquals("lolcat", reader.readUTF());
assertTrue(reader.readBoolean());
assertEquals(4, reader.readInt());
assertEquals("blob", readBlob(reader, 4));
}
private void assertHeader(DataInputStream reader) throws IOException {
assertEquals(COLUMN_NAMES.length, reader.readInt());
for (int i = 0; i < COLUMN_NAMES.length; i++) {
assertEquals(COLUMN_NAMES[i], reader.readUTF());
assertEquals(COLUMN_TYPES[i], reader.readByte());
}
}
private String readBlob(InputStream reader, int length) throws Exception {
if (length == 0) {
return "";
}
byte[] blob = new byte[length];
assertEquals(length, reader.read(blob));
return new String(blob);
}
}
@@ -0,0 +1,293 @@
/*
* Copyright 2010 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 com.google.android.apps.mytracks.io.backup;
import com.google.android.apps.mytracks.content.ContentTypeIds;
import android.content.ContentValues;
import android.net.Uri;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import junit.framework.TestCase;
/**
* Tests for {@link DatabaseImporter}.
*
* @author Rodrigo Damazio
*/
public class DatabaseImporterTest extends TestCase {
private static final Uri DESTINATION_URI = Uri.parse("http://www.google.com/");
private static final int TEST_BULK_SIZE = 10;
private ArrayList<ContentValues> insertedValues;
private class TestableDatabaseImporter extends DatabaseImporter {
public TestableDatabaseImporter(boolean readNullFields) {
super(DESTINATION_URI, null, readNullFields, TEST_BULK_SIZE);
}
@Override
protected void doBulkInsert(ContentValues[] values) {
insertedValues.ensureCapacity(insertedValues.size() + values.length);
// We need to make a copy of the values since the objects are re-used
for (ContentValues contentValues : values) {
insertedValues.add(new ContentValues(contentValues));
}
}
}
@Override
protected void setUp() throws Exception {
super.setUp();
insertedValues = new ArrayList<ContentValues>();
}
public void testImportAllRows() throws Exception {
testImportAllRows(false);
}
public void testImportAllRows_readNullFields() throws Exception {
testImportAllRows(true);
}
private void testImportAllRows(boolean readNullFields) throws Exception {
// Create a fake data stream to be read
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(1024);
DataOutputStream writer = new DataOutputStream(outputStream);
writeFullHeader(writer);
// Add the number of rows
writer.writeInt(2);
// Add a row with all fields present
writer.writeLong(0x7F);
writer.writeInt(42);
writer.writeBoolean(true);
writer.writeUTF("lolcat");
writer.writeFloat(3.1415f);
writer.writeDouble(2.72);
writer.writeLong(123456789L);
writer.writeInt(4);
writer.writeBytes("blob");
// Add a row with some missing fields
writer.writeLong(0x15);
writer.writeInt(42);
if (readNullFields) writer.writeBoolean(false);
writer.writeUTF("lolcat");
if (readNullFields) writer.writeFloat(0.0f);
writer.writeDouble(2.72);
if (readNullFields) writer.writeLong(0L);
if (readNullFields) writer.writeInt(0); // empty blob
writer.flush();
// Do the importing
DatabaseImporter importer = new TestableDatabaseImporter(readNullFields);
byte[] dataBytes = outputStream.toByteArray();
importer.importAllRows(new DataInputStream(new ByteArrayInputStream(dataBytes)));
assertEquals(2, insertedValues.size());
// Verify the first row
ContentValues value = insertedValues.get(0);
assertEquals(value.toString(), 7, value.size());
assertValue(42, "col1", value);
assertValue(true, "col2", value);
assertValue("lolcat", "col3", value);
assertValue(3.1415f, "col4", value);
assertValue(2.72, "col5", value);
assertValue(123456789L, "col6", value);
assertBlobValue("blob", "col7", value);
// Verify the second row
value = insertedValues.get(1);
assertEquals(value.toString(), 3, value.size());
assertValue(42, "col1", value);
assertValue("lolcat", "col3", value);
assertValue(2.72, "col5", value);
}
public void testImportAllRows_noRows() throws Exception {
// Create a fake data stream to be read
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(1024);
DataOutputStream writer = new DataOutputStream(outputStream);
writeFullHeader(writer);
// Add the number of rows
writer.writeInt(0);
writer.flush();
// Do the importing
DatabaseImporter importer = new TestableDatabaseImporter(false);
byte[] dataBytes = outputStream.toByteArray();
importer.importAllRows(new DataInputStream(new ByteArrayInputStream(dataBytes)));
assertTrue(insertedValues.isEmpty());
}
public void testImportAllRows_emptyRows() throws Exception {
testImportAllRowsWithEmptyRows(false);
}
public void testImportAllRows_emptyRowsWithNulls() throws Exception {
testImportAllRowsWithEmptyRows(true);
}
private void testImportAllRowsWithEmptyRows(boolean readNullFields) throws Exception {
// Create a fake data stream to be read
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(1024);
DataOutputStream writer = new DataOutputStream(outputStream);
writeFullHeader(writer);
// Add the number of rows
writer.writeInt(3);
// Add 2 rows with no fields
for (int i = 0; i < 2; i++) {
writer.writeLong(0);
if (readNullFields) {
writer.writeInt(0);
writer.writeBoolean(false);
writer.writeUTF("");
writer.writeFloat(0.0f);
writer.writeDouble(0.0);
writer.writeLong(0L);
writer.writeInt(0); // empty blob
}
}
// Add a row with some missing fields
writer.writeLong(0x15);
writer.writeInt(42);
if (readNullFields) writer.writeBoolean(false);
writer.writeUTF("lolcat");
if (readNullFields) writer.writeFloat(0.0f);
writer.writeDouble(2.72);
if (readNullFields) writer.writeLong(0L);
if (readNullFields) writer.writeInt(0); // empty blob
writer.flush();
// Do the importing
DatabaseImporter importer = new TestableDatabaseImporter(readNullFields);
byte[] dataBytes = outputStream.toByteArray();
importer.importAllRows(new DataInputStream(new ByteArrayInputStream(dataBytes)));
assertEquals(insertedValues.toString(), 3, insertedValues.size());
ContentValues value = insertedValues.get(0);
assertEquals(value.toString(), 0, value.size());
value = insertedValues.get(1);
assertEquals(value.toString(), 0, value.size());
// Verify the third row (only one with values)
value = insertedValues.get(2);
assertEquals(value.toString(), 3, value.size());
assertFalse(value.containsKey("col2"));
assertFalse(value.containsKey("col4"));
assertFalse(value.containsKey("col6"));
assertValue(42, "col1", value);
assertValue("lolcat", "col3", value);
assertValue(2.72, "col5", value);
}
public void testImportAllRows_bulks() throws Exception {
// Create a fake data stream to be read
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(1024);
DataOutputStream writer = new DataOutputStream(outputStream);
// Add the header
writer.writeInt(2);
writer.writeUTF("col1");
writer.writeByte(ContentTypeIds.INT_TYPE_ID);
writer.writeUTF("col2");
writer.writeByte(ContentTypeIds.STRING_TYPE_ID);
// Add lots of rows (so the insertions are split in multiple bulks)
int numRows = TEST_BULK_SIZE * 5 / 2;
writer.writeInt(numRows);
for (int i = 0; i < numRows; i++) {
writer.writeLong(3);
writer.writeInt(i);
writer.writeUTF(Integer.toString(i * 2));
}
writer.flush();
// Do the importing
DatabaseImporter importer = new TestableDatabaseImporter(false);
byte[] dataBytes = outputStream.toByteArray();
importer.importAllRows(new DataInputStream(new ByteArrayInputStream(dataBytes)));
// Verify the rows
assertEquals(numRows, insertedValues.size());
for (int i = 0; i < numRows; i++) {
ContentValues value = insertedValues.get(i);
assertEquals(value.toString(), 2, value.size());
assertValue(i, "col1", value);
assertValue(Integer.toString(i * 2), "col2", value);
}
}
private void writeFullHeader(DataOutputStream writer) throws IOException {
// Add the header
writer.writeInt(7);
writer.writeUTF("col1");
writer.writeByte(ContentTypeIds.INT_TYPE_ID);
writer.writeUTF("col2");
writer.writeByte(ContentTypeIds.BOOLEAN_TYPE_ID);
writer.writeUTF("col3");
writer.writeByte(ContentTypeIds.STRING_TYPE_ID);
writer.writeUTF("col4");
writer.writeByte(ContentTypeIds.FLOAT_TYPE_ID);
writer.writeUTF("col5");
writer.writeByte(ContentTypeIds.DOUBLE_TYPE_ID);
writer.writeUTF("col6");
writer.writeByte(ContentTypeIds.LONG_TYPE_ID);
writer.writeUTF("col7");
writer.writeByte(ContentTypeIds.BLOB_TYPE_ID);
}
private <T> void assertValue(T expectedValue, String name, ContentValues values) {
@SuppressWarnings("unchecked")
T value = (T) values.get(name);
assertNotNull(value);
assertEquals(expectedValue, value);
}
private void assertBlobValue(String expectedValue, String name, ContentValues values ){
byte[] blob = values.getAsByteArray(name);
assertEquals(expectedValue, new String(blob));
}
}
@@ -0,0 +1,212 @@
/*
* Copyright 2010 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 com.google.android.apps.mytracks.io.backup;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.test.AndroidTestCase;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Tests for {@link PreferenceBackupHelper}.
*
* @author Rodrigo Damazio
*/
public class PreferenceBackupHelperTest extends AndroidTestCase {
private Map<String, ?> preferenceValues;
private SharedPreferences preferences;
private PreferenceBackupHelper preferenceBackupHelper;
/**
* Mock shared preferences editor which does not persist state.
*/
private class MockPreferenceEditor implements SharedPreferences.Editor {
private Map<String, Object> newPreferences = new HashMap<String, Object>(preferenceValues);
@Override
public Editor clear() {
newPreferences.clear();
return this;
}
@Override
public boolean commit() {
apply();
return true;
}
@Override
public void apply() {
preferenceValues = newPreferences;
}
@Override
public Editor putBoolean(String key, boolean value) {
return put(key, value);
}
@Override
public Editor putFloat(String key, float value) {
return put(key, value);
}
@Override
public Editor putInt(String key, int value) {
return put(key, value);
}
@Override
public Editor putLong(String key, long value) {
return put(key, value);
}
@Override
public Editor putString(String key, String value) {
return put(key, value);
}
public Editor putStringSet(String key, Set<String> value) {
return put(key, value);
}
private <T> Editor put(String key, T value) {
newPreferences.put(key, value);
return this;
}
@Override
public Editor remove(String key) {
newPreferences.remove(key);
return this;
}
}
/**
* Mock shared preferences which does not persist state.
*/
private class MockPreferences implements SharedPreferences {
@Override
public boolean contains(String key) {
return preferenceValues.containsKey(key);
}
@Override
public Editor edit() {
return new MockPreferenceEditor();
}
@Override
public Map<String, ?> getAll() {
return preferenceValues;
}
@Override
public boolean getBoolean(String key, boolean defValue) {
return get(key, defValue);
}
@Override
public float getFloat(String key, float defValue) {
return get(key, defValue);
}
@Override
public int getInt(String key, int defValue) {
return get(key, defValue);
}
@Override
public long getLong(String key, long defValue) {
return get(key, defValue);
}
@Override
public String getString(String key, String defValue) {
return get(key, defValue);
}
public Set<String> getStringSet(String key, Set<String> defValue) {
return get(key, defValue);
}
@Override
public void registerOnSharedPreferenceChangeListener(
OnSharedPreferenceChangeListener listener) {
throw new UnsupportedOperationException();
}
@Override
public void unregisterOnSharedPreferenceChangeListener(
OnSharedPreferenceChangeListener listener) {
throw new UnsupportedOperationException();
}
@SuppressWarnings("unchecked")
private <T> T get(String key, T defValue) {
Object value = preferenceValues.get(key);
if (value == null) return defValue;
return (T) value;
}
}
@Override
protected void setUp() throws Exception {
super.setUp();
preferenceValues = new HashMap<String, Object>();
preferences = new MockPreferences();
preferenceBackupHelper = new PreferenceBackupHelper(getContext());
}
public void testExportImportPreferences() throws Exception {
// Populate with some initial values
Editor editor = preferences.edit();
editor.clear();
editor.putBoolean("bool1", true);
editor.putBoolean("bool2", false);
editor.putFloat("flt1", 3.14f);
editor.putInt("int1", 42);
editor.putLong("long1", 123456789L);
editor.putString("str1", "lolcat");
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
// Export it
byte[] exported = preferenceBackupHelper.exportPreferences(preferences);
// Mess with the previous values
editor = preferences.edit();
editor.clear();
editor.putString("str2", "Shouldn't be there after restore");
editor.putBoolean("bool2", true);
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
// Import it back
preferenceBackupHelper.importPreferences(exported, preferences);
assertFalse(preferences.contains("str2"));
assertTrue(preferences.getBoolean("bool1", false));
assertFalse(preferences.getBoolean("bool2", true));
assertEquals(3.14f, preferences.getFloat("flt1", 0.0f));
assertEquals(42, preferences.getInt("int1", 0));
assertEquals(123456789L, preferences.getLong("long1", 0));
assertEquals("lolcat", preferences.getString("str1", ""));
}
}
@@ -0,0 +1,164 @@
/*
* 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 com.google.android.apps.mytracks.io.file;
import static com.google.android.testing.mocking.AndroidMock.eq;
import static com.google.android.testing.mocking.AndroidMock.expect;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.Factory;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.content.WaypointsColumns;
import com.google.android.apps.mytracks.testing.TestingProviderUtilsFactory;
import com.google.android.testing.mocking.AndroidMock;
import com.google.android.testing.mocking.UsesMocks;
import android.content.ContentUris;
import android.location.Location;
import android.location.LocationManager;
import android.net.Uri;
import android.test.AndroidTestCase;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.SimpleTimeZone;
import org.easymock.Capture;
/**
* Abstract class for testing importer.
*
* @author Jimmy Shih.
*/
public class AbstractTestImporter extends AndroidTestCase {
protected static final String TRACK_NAME_0 = "blablub";
protected static final String TRACK_DESCRIPTION_0 = "s'Laebe isch koi Schlotzer";
protected static final String TRACK_NAME_1 = "another track";
protected static final String TRACK_DESCRIPTION_1 = "another description";
protected static final double TRACK_LATITUDE = 48.768364;
protected static final double TRACK_LONGITUDE = 9.177886;
protected static final double TRACK_ELEVATION = 324.0;
protected static final String TRACK_TIME_0 = "2010-04-22T18:21:00Z";
protected static final String TRACK_TIME_1 = "2010-04-22T18:21:50.123";
protected static final String TRACK_TIME_2 = "2010-04-22T18:23:00.123";
protected static final String TRACK_TIME_3 = "2010-04-22T18:24:50.123";
protected static final SimpleDateFormat DATE_FORMAT_0 = new SimpleDateFormat(
"yyyy-MM-dd'T'hh:mm:ss'Z'", Locale.US);
protected static final SimpleDateFormat DATE_FORMAT_1 = new SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.US);
static {
/*
* We can't omit the timezones in the test, otherwise it'll use the local
* timezone and fail depending on where the test runner is.
*/
SimpleTimeZone utc = new SimpleTimeZone(0, "UTC");
DATE_FORMAT_0.setTimeZone(utc);
DATE_FORMAT_1.setTimeZone(utc);
}
protected static final long TRACK_ID_0 = 1;
protected static final long TRACK_ID_1 = 2;
protected static final long TRACK_POINT_ID_0 = 1;
protected static final long TRACK_POINT_ID_1 = 2;
protected static final long TRACK_POINT_ID_3 = 4;
protected static final long WAYPOINT_ID_0 = 1;
protected static final Uri TRACK_ID_0_URI = ContentUris.appendId(
TracksColumns.CONTENT_URI.buildUpon(), TRACK_ID_0).build();
protected static final Uri TRACK_ID_1_URI = ContentUris.appendId(
TracksColumns.CONTENT_URI.buildUpon(), TRACK_ID_1).build();
protected static final Uri WAYPOINT_ID_O_URI = ContentUris.appendId(
WaypointsColumns.CONTENT_URI.buildUpon(), WAYPOINT_ID_0).build();
protected MyTracksProviderUtils myTracksProviderUtils;
private Factory oldMyTracksProviderUtilsFactory;
@UsesMocks(MyTracksProviderUtils.class)
@Override
protected void setUp() throws Exception {
super.setUp();
myTracksProviderUtils = AndroidMock.createMock(MyTracksProviderUtils.class);
oldMyTracksProviderUtilsFactory = TestingProviderUtilsFactory.installWithInstance(
myTracksProviderUtils);
}
@Override
protected void tearDown() throws Exception {
TestingProviderUtilsFactory.restoreOldFactory(oldMyTracksProviderUtilsFactory);
super.tearDown();
}
protected Location createLocation(int index, long time) {
Location location = new Location(LocationManager.GPS_PROVIDER);
location.setLatitude(TRACK_LATITUDE + index);
location.setLongitude(TRACK_LONGITUDE + index);
location.setAltitude(TRACK_ELEVATION + index);
location.setTime(time);
return location;
}
/**
* Expects the first track point to be added.
*
* @param location the location
* @param trackId the track id
* @param trackPointId the track point id
*/
protected void expectFirstTrackPoint(Location location, long trackId, long trackPointId) {
expect(myTracksProviderUtils.bulkInsertTrackPoint(
location != null ? LocationsMatcher.eqLoc(location) : (Location[]) AndroidMock.anyObject(),
eq(1), eq(trackId))).andReturn(1);
expect(myTracksProviderUtils.getFirstTrackPointId(trackId)).andReturn(trackPointId);
expect(myTracksProviderUtils.getLastTrackPointId(trackId)).andReturn(trackPointId);
}
/**
* Expects the track to be updated.
*
* @param track the track
* @param lastTrack true if it is the last track in the gpx
* @param trackId the track id
*/
protected void expectUpdateTrack(Capture<Track> track, boolean lastTrack, long trackId) {
myTracksProviderUtils.updateTrack(AndroidMock.capture(track));
expect(myTracksProviderUtils.insertWaypoint((Waypoint) AndroidMock.anyObject()))
.andReturn(WAYPOINT_ID_O_URI);
if (lastTrack) {
// Return null to not add waypoints
expect(myTracksProviderUtils.getTrack(trackId)).andReturn(null);
}
}
protected void verifyTrack(Track track, String name, String description, long time) {
assertEquals(name, track.getName());
assertEquals(description, track.getDescription());
if (time != -1L) {
assertEquals(time, track.getTripStatistics().getStartTime());
}
assertNotSame(-1, track.getStartId());
assertNotSame(-1, track.getStopId());
}
}
@@ -0,0 +1,88 @@
/*
* 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 com.google.android.apps.mytracks.io.file;
/**
* Tests for {@link CsvTrackWriter}.
*
* @author Rodrigo Damazio
*/
public class CsvTrackWriterTest extends TrackFormatWriterTest {
private static final String BEGIN_TAG = "\"";
private static final String END_TAG = "\"\n";
private static final String SEPARATOR = "\",\"";
public void testCsvOutput() throws Exception {
String expectedTrackHeader = getExpectedLine(
"Name", "Activity type", "Description");
String expectedTrack = getExpectedLine(TRACK_NAME, TRACK_CATEGORY, TRACK_DESCRIPTION);
String expectedMarkerHeader = getExpectedLine("Name",
"Marker type",
"Description",
"Latitude (deg)",
"Longitude (deg)",
"Altitude (m)",
"Bearing (deg)",
"Accuracy (m)",
"Speed (m/s)",
"Time");
String expectedMarker1 = getExpectedLine(WAYPOINT1_NAME, WAYPOINT1_CATEGORY,
WAYPOINT1_DESCRIPTION, "1.0", "-1.0", "10.0", "100.0", "1,000", "10,000",
"1970-01-01T00:01:40.000Z");
String expectedMarker2 = getExpectedLine(WAYPOINT2_NAME, WAYPOINT2_CATEGORY,
WAYPOINT2_DESCRIPTION, "2.0", "-2.0", "20.0", "200.0", "2,000", "20,000",
"1970-01-01T00:03:20.000Z");
String expectedPointHeader = getExpectedLine("Segment", "Point", "Latitude (deg)",
"Longitude (deg)", "Altitude (m)", "Bearing (deg)", "Accuracy (m)", "Speed (m/s)", "Time",
"Power (W)", "Cadence (rpm)", "Heart rate (bpm)");
String expectedPoint1 = getExpectedLine("1", "1", "0.0", "0.0", "0.0", "0.0", "0", "0",
"1970-01-01T00:00:00.000Z", "100.0", "200.0", "300.0");
String expectedPoint2 = getExpectedLine("1", "2", "1.0", "-1.0", "10.0", "100.0", "1,000",
"10,000", "1970-01-01T00:01:40.000Z", "101.0", "201.0", "301.0");
String expectedPoint3 = getExpectedLine("2", "1", "2.0", "-2.0", "20.0", "200.0", "2,000",
"20,000", "1970-01-01T00:03:20.000Z", "102.0", "202.0", "302.0");
String expectedPoint4 = getExpectedLine("2", "2", "3.0", "-3.0", "30.0", "300.0", "3,000",
"30,000", "1970-01-01T00:05:00.000Z", "103.0", "203.0", "303.0");
String expected = expectedTrackHeader + expectedTrack + "\n"
+ expectedMarkerHeader + expectedMarker1 + expectedMarker2 + "\n"
+ expectedPointHeader + expectedPoint1 + expectedPoint2 + expectedPoint3 + expectedPoint4;
CsvTrackWriter writer = new CsvTrackWriter(getContext());
assertEquals(expected, writeTrack(writer));
}
/**
* Gets the expected CSV line from a list of expected values.
*
* @param values expected values
*/
private String getExpectedLine(String... values) {
StringBuilder builder = new StringBuilder();
builder.append(BEGIN_TAG);
boolean first = true;
for (String value : values) {
if (!first) {
builder.append(SEPARATOR);
}
first = false;
builder.append(value);
}
builder.append(END_TAG);
return builder.toString();
}
}
@@ -0,0 +1,289 @@
/*
* Copyright 2010 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 com.google.android.apps.mytracks.io.file;
import static com.google.android.testing.mocking.AndroidMock.eq;
import static com.google.android.testing.mocking.AndroidMock.expect;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.testing.mocking.AndroidMock;
import android.location.Location;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import org.easymock.Capture;
import org.xml.sax.SAXException;
/**
* Tests for {@link GpxImporter}.
*
* @author Steffen Horlacher
*/
public class GpxImporterTest extends AbstractTestImporter {
private static String getNameAndDescription(String name, String description) {
return "<name><![CDATA[" + name + "]]></name>" + "<desc><![CDATA[" + description + "]]></desc>";
}
private static String getTrackPoint(int index, String time) {
String latitude = Double.toString(TRACK_LATITUDE + index);
String longitude = Double.toString(TRACK_LONGITUDE + index);
String elevation = Double.toString(TRACK_ELEVATION + index);
StringBuffer buffer = new StringBuffer();
buffer.append(
"<trkpt lat=\"" + latitude + "\" lon=\"" + longitude + "\"><ele>" + elevation + "</ele>");
if (time != null) {
buffer.append("<time>" + time + "</time>");
}
buffer.append("</trkpt>");
return buffer.toString();
}
private static final String VALID_ONE_TRACK_ONE_SEGMENT_GPX = "<gpx><trk>"
+ getNameAndDescription(TRACK_NAME_0, TRACK_DESCRIPTION_0) + "<trkseg>"
+ getTrackPoint(0, TRACK_TIME_0) + getTrackPoint(1, TRACK_TIME_1) + "</trkseg></trk></gpx>";
private static final String VALID_ONE_TRACK_TWO_SEGMENTS_GPX = "<gpx><trk>"
+ getNameAndDescription(TRACK_NAME_0, TRACK_DESCRIPTION_0) + "<trkseg>"
+ getTrackPoint(0, TRACK_TIME_0) + getTrackPoint(1, TRACK_TIME_1) + "</trkseg><trkseg>"
+ getTrackPoint(2, TRACK_TIME_2) + getTrackPoint(3, TRACK_TIME_3) + "</trkseg></trk></gpx>";
private static final String VALID_ONE_TRACK_TWO_SEGMENTS_NO_TIME_GPX = "<gpx><trk>"
+ getNameAndDescription(TRACK_NAME_0, TRACK_DESCRIPTION_0) + "<trkseg>"
+ getTrackPoint(0, null) + getTrackPoint(1, null) + "</trkseg><trkseg>"
+ getTrackPoint(2, null) + getTrackPoint(3, null) + "</trkseg></trk></gpx>";
private static final String VALID_TWO_TRACKS_GPX = "<gpx><trk>"
+ getNameAndDescription(TRACK_NAME_0, TRACK_DESCRIPTION_0) + "<trkseg>"
+ getTrackPoint(0, TRACK_TIME_0) + "</trkseg></trk><trk>"
+ getNameAndDescription(TRACK_NAME_1, TRACK_DESCRIPTION_1) + "<trkseg>"
+ getTrackPoint(1, TRACK_TIME_1) + "</trkseg></trk></gpx>";
private static final String INVALID_XML_GPX = VALID_ONE_TRACK_ONE_SEGMENT_GPX.substring(
0, VALID_ONE_TRACK_ONE_SEGMENT_GPX.length() - 50);
private static final String INVALID_LOCATION_GPX = VALID_ONE_TRACK_ONE_SEGMENT_GPX.replaceAll(
Double.toString(TRACK_LATITUDE), "1000.0");
private static final String INVALID_TIME_GPX = VALID_ONE_TRACK_ONE_SEGMENT_GPX.replaceAll(
TRACK_TIME_0, "invalid");
private static final String INVALID_ALTITUDE_GPX = VALID_ONE_TRACK_ONE_SEGMENT_GPX.replaceAll(
Double.toString(TRACK_ELEVATION), "invalid");
private static final String INVALID_LATITUDE_GPX = VALID_ONE_TRACK_ONE_SEGMENT_GPX.replaceAll(
Double.toString(TRACK_LATITUDE), "invalid");
private static final String INVALID_LONGITUDE_GPX = VALID_ONE_TRACK_ONE_SEGMENT_GPX.replaceAll(
Double.toString(TRACK_LONGITUDE), "invalid");
/**
* Tests one track with one segment.
*/
public void testOneTrackOneSegment() throws Exception {
Capture<Track> track = new Capture<Track>();
Location location0 = createLocation(0, DATE_FORMAT_0.parse(TRACK_TIME_0).getTime());
Location location1 = createLocation(1, DATE_FORMAT_1.parse(TRACK_TIME_1).getTime());
expect(myTracksProviderUtils.insertTrack((Track) AndroidMock.anyObject()))
.andReturn(TRACK_ID_0_URI);
expectFirstTrackPoint(location0, TRACK_ID_0, TRACK_POINT_ID_0);
// A flush happens at the end
expect(myTracksProviderUtils.bulkInsertTrackPoint(
LocationsMatcher.eqLoc(location1), eq(1), eq(TRACK_ID_0))).andReturn(1);
expect(myTracksProviderUtils.getLastTrackPointId(TRACK_ID_0)).andReturn(TRACK_POINT_ID_1);
expectUpdateTrack(track, true, TRACK_ID_0);
AndroidMock.replay(myTracksProviderUtils);
InputStream inputStream = new ByteArrayInputStream(VALID_ONE_TRACK_ONE_SEGMENT_GPX.getBytes());
GpxImporter gpxImporter = new GpxImporter(getContext(), myTracksProviderUtils);
long[] trackIds = gpxImporter.importFile(inputStream);
assertEquals(1, trackIds.length);
assertEquals(TRACK_ID_0, trackIds[0]);
long time0 = DATE_FORMAT_0.parse(TRACK_TIME_0).getTime();
long time1 = DATE_FORMAT_1.parse(TRACK_TIME_1).getTime();
assertEquals(time1 - time0, track.getValue().getTripStatistics().getTotalTime());
AndroidMock.verify(myTracksProviderUtils);
verifyTrack(track.getValue(), TRACK_NAME_0, TRACK_DESCRIPTION_0, time0);
}
/**
* Tests one track with two segments.
*/
public void testOneTrackTwoSegments() throws Exception {
Capture<Track> track = new Capture<Track>();
Location location0 = createLocation(0, DATE_FORMAT_0.parse(TRACK_TIME_0).getTime());
expect(myTracksProviderUtils.insertTrack((Track) AndroidMock.anyObject()))
.andReturn(TRACK_ID_0_URI);
expectFirstTrackPoint(location0, TRACK_ID_0, TRACK_POINT_ID_0);
// A flush happens at the end
expect(myTracksProviderUtils.bulkInsertTrackPoint(
(Location[]) AndroidMock.anyObject(), eq(5), eq(TRACK_ID_0))).andStubReturn(5);
expect(myTracksProviderUtils.getLastTrackPointId(TRACK_ID_0)).andReturn(TRACK_POINT_ID_3);
expectUpdateTrack(track, true, TRACK_ID_0);
AndroidMock.replay(myTracksProviderUtils);
InputStream inputStream = new ByteArrayInputStream(VALID_ONE_TRACK_TWO_SEGMENTS_GPX.getBytes());
GpxImporter gpxImporter = new GpxImporter(getContext(), myTracksProviderUtils);
long[] trackIds = gpxImporter.importFile(inputStream);
assertEquals(1, trackIds.length);
assertEquals(TRACK_ID_0, trackIds[0]);
long time0 = DATE_FORMAT_0.parse(TRACK_TIME_0).getTime();
long time1 = DATE_FORMAT_1.parse(TRACK_TIME_1).getTime();
long time2 = DATE_FORMAT_1.parse(TRACK_TIME_2).getTime();
long time3 = DATE_FORMAT_1.parse(TRACK_TIME_3).getTime();
assertEquals(
time1 - time0 + time3 - time2, track.getValue().getTripStatistics().getTotalTime());
AndroidMock.verify(myTracksProviderUtils);
verifyTrack(track.getValue(), TRACK_NAME_0, TRACK_DESCRIPTION_0,
DATE_FORMAT_0.parse(TRACK_TIME_0).getTime());
}
/**
* Tests one track with two segments, but no time in the track points.
*/
public void testOneTrackTwoSegmentsNoTime() throws Exception {
Capture<Track> track = new Capture<Track>();
expect(myTracksProviderUtils.insertTrack((Track) AndroidMock.anyObject()))
.andReturn(TRACK_ID_0_URI);
expectFirstTrackPoint(null, TRACK_ID_0, TRACK_POINT_ID_0);
// A flush happens at the end
expect(myTracksProviderUtils.bulkInsertTrackPoint(
(Location[]) AndroidMock.anyObject(), eq(5), eq(TRACK_ID_0))).andStubReturn(5);
expect(myTracksProviderUtils.getLastTrackPointId(TRACK_ID_0)).andReturn(TRACK_POINT_ID_3);
expectUpdateTrack(track, true, TRACK_ID_0);
AndroidMock.replay(myTracksProviderUtils);
InputStream inputStream = new ByteArrayInputStream(
VALID_ONE_TRACK_TWO_SEGMENTS_NO_TIME_GPX.getBytes());
GpxImporter gpxImporter = new GpxImporter(getContext(), myTracksProviderUtils);
long[] trackIds = gpxImporter.importFile(inputStream);
assertEquals(1, trackIds.length);
assertEquals(TRACK_ID_0, trackIds[0]);
assertEquals(0, track.getValue().getTripStatistics().getTotalTime());
AndroidMock.verify(myTracksProviderUtils);
verifyTrack(track.getValue(), TRACK_NAME_0, TRACK_DESCRIPTION_0, -1L);
}
/**
* Tests two tracks.
*/
public void testTwoTracks() throws Exception {
Capture<Track> track0 = new Capture<Track>();
Capture<Track> track1 = new Capture<Track>();
Location location0 = createLocation(0, DATE_FORMAT_0.parse(TRACK_TIME_0).getTime());
Location location1 = createLocation(1, DATE_FORMAT_1.parse(TRACK_TIME_1).getTime());
expect(myTracksProviderUtils.insertTrack((Track) AndroidMock.anyObject()))
.andReturn(TRACK_ID_0_URI);
expectFirstTrackPoint(location0, TRACK_ID_0, TRACK_POINT_ID_0);
expectUpdateTrack(track0, false, TRACK_ID_0);
expect(myTracksProviderUtils.insertTrack((Track) AndroidMock.anyObject()))
.andReturn(TRACK_ID_1_URI);
expectFirstTrackPoint(location1, TRACK_ID_1, TRACK_POINT_ID_1);
expectUpdateTrack(track1, true, TRACK_ID_1);
AndroidMock.replay(myTracksProviderUtils);
InputStream inputStream = new ByteArrayInputStream(VALID_TWO_TRACKS_GPX.getBytes());
GpxImporter gpxImporter = new GpxImporter(getContext(), myTracksProviderUtils);
long[] trackIds = gpxImporter.importFile(inputStream);
assertEquals(2, trackIds.length);
assertEquals(TRACK_ID_0, trackIds[0]);
assertEquals(TRACK_ID_1, trackIds[1]);
AndroidMock.verify(myTracksProviderUtils);
}
/**
* Test an invalid xml input.
*/
public void testInvalidXml() throws Exception {
testInvalidGpx(INVALID_XML_GPX);
}
/**
* Test an invalid location.
*/
public void testInvalidLocation() throws Exception {
testInvalidGpx(INVALID_LOCATION_GPX);
}
/**
* Test an invalid time.
*/
public void testInvalidTime() throws Exception {
testInvalidGpx(INVALID_TIME_GPX);
}
/**
* Test an invalid altitude.
*/
public void testInvalidAltitude() throws Exception {
testInvalidGpx(INVALID_ALTITUDE_GPX);
}
/**
* Test an invalid latitude.
*/
public void testInvalidLatitude() throws Exception {
testInvalidGpx(INVALID_LATITUDE_GPX);
}
/**
* Test an invalid longitude.
*/
public void testInvalidLongitude() throws Exception {
testInvalidGpx(INVALID_LONGITUDE_GPX);
}
private void testInvalidGpx(String xml) throws Exception {
expect(myTracksProviderUtils.insertTrack((Track) AndroidMock.anyObject()))
.andReturn(TRACK_ID_0_URI);
// For the following, use StubReturn since we don't care whether they are
// invoked or not.
expect(myTracksProviderUtils.bulkInsertTrackPoint(
(Location[]) AndroidMock.anyObject(), AndroidMock.anyInt(), AndroidMock.anyLong()))
.andStubReturn(1);
expect(myTracksProviderUtils.getFirstTrackPointId(TRACK_ID_0)).andStubReturn(TRACK_POINT_ID_0);
expect(myTracksProviderUtils.getLastTrackPointId(TRACK_ID_0)).andStubReturn(TRACK_POINT_ID_0);
myTracksProviderUtils.deleteTrack(TRACK_ID_0);
AndroidMock.replay(myTracksProviderUtils);
InputStream inputStream = new ByteArrayInputStream(xml.getBytes());
try {
GpxImporter gpxImporter = new GpxImporter(getContext(), myTracksProviderUtils);
gpxImporter.importFile(inputStream);
} catch (SAXException e) {
// expected
}
AndroidMock.verify(myTracksProviderUtils);
}
}
@@ -0,0 +1,76 @@
/*
* Copyright 2010 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 com.google.android.apps.mytracks.io.file;
import java.util.List;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Tests for {@link GpxTrackWriter}.
*
* @author Rodrigo Damazio
*/
public class GpxTrackWriterTest extends TrackFormatWriterTest {
public void testXmlOutput() throws Exception {
TrackFormatWriter writer = new GpxTrackWriter(getContext());
String result = writeTrack(writer);
Document doc = parseXmlDocument(result);
Element gpxTag = getChildElement(doc, "gpx");
Element trackTag = getChildElement(gpxTag, "trk");
assertEquals(TRACK_NAME, getChildTextValue(trackTag, "name"));
assertEquals(TRACK_DESCRIPTION, getChildTextValue(trackTag, "desc"));
List<Element> segmentTags = getChildElements(trackTag, "trkseg", 2);
List<Element> segPointTags = getChildElements(segmentTags.get(0), "trkpt", 2);
assertTagMatchesLocation(segPointTags.get(0), "0", "0", "1970-01-01T00:00:00.000Z", "0");
assertTagMatchesLocation(segPointTags.get(1), "1", "-1", "1970-01-01T00:01:40.000Z", "10");
segPointTags = getChildElements(segmentTags.get(1), "trkpt", 2);
assertTagMatchesLocation(segPointTags.get(0), "2", "-2", "1970-01-01T00:03:20.000Z", "20");
assertTagMatchesLocation(segPointTags.get(1), "3", "-3", "1970-01-01T00:05:00.000Z", "30");
List<Element> waypointTags = getChildElements(gpxTag, "wpt", 2);
Element wptTag = waypointTags.get(0);
assertEquals(WAYPOINT1_NAME, getChildTextValue(wptTag, "name"));
assertEquals(WAYPOINT1_DESCRIPTION, getChildTextValue(wptTag, "desc"));
assertTagMatchesLocation(wptTag, "1", "-1", "1970-01-01T00:01:40.000Z", "10");
wptTag = waypointTags.get(1);
assertEquals(WAYPOINT2_NAME, getChildTextValue(wptTag, "name"));
assertEquals(WAYPOINT2_DESCRIPTION, getChildTextValue(wptTag, "desc"));
assertTagMatchesLocation(wptTag, "2", "-2", "1970-01-01T00:03:20.000Z", "20");
}
/**
* Asserts that the given tag describes a location.
*
* @param tag the tag
* @param latitude the location's latitude
* @param longitude the location's longitude
* @param time the location's time
* @param elevation the location's elevation
*/
private void assertTagMatchesLocation(
Element tag, String latitude, String longitude, String time, String elevation) {
assertEquals(latitude, tag.getAttribute("lat"));
assertEquals(longitude, tag.getAttribute("lon"));
assertEquals(time, getChildTextValue(tag, "time"));
assertEquals(elevation, getChildTextValue(tag, "ele"));
}
}
@@ -0,0 +1,137 @@
/*
* 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 com.google.android.apps.mytracks.io.file;
import static com.google.android.testing.mocking.AndroidMock.eq;
import static com.google.android.testing.mocking.AndroidMock.expect;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.testing.mocking.AndroidMock;
import android.location.Location;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import org.easymock.Capture;
/**
* Tests for {@link KmlImporter}.
*
* @author Jimmy Shih
*/
public class KmlImporterTest extends AbstractTestImporter {
private static String getNameAndDescription(String name, String description) {
return "<name><![CDATA[" + name + "]]></name><description><![CDATA[" + description
+ "]]></description>";
}
private static String getTrackPoint(int index, String time) {
String latitude = Double.toString(TRACK_LATITUDE + index);
String longitude = Double.toString(TRACK_LONGITUDE + index);
String altitude = Double.toString(TRACK_ELEVATION + index);
StringBuffer buffer = new StringBuffer();
buffer.append("<when>" + time + "</when>" + "<gx:coord>" + longitude + " " + latitude + " "
+ altitude + "</gx:coord>");
return buffer.toString();
}
private static final String VALID_ONE_TRACK_ONE_SEGMENT_GPX =
"<kml xmlns:gx=\"http://www.google.com/kml/ext/2.2\"><Placemark>"
+ getNameAndDescription(TRACK_NAME_0, TRACK_DESCRIPTION_0) + "<gx:MultiTrack><gx:Track>"
+ getTrackPoint(0, TRACK_TIME_0) + getTrackPoint(1, TRACK_TIME_1)
+ "</gx:Track></gx:MultiTrack></Placemark></kml>";
private static final String VALID_ONE_TRACK_TWO_SEGMENTS_GPX =
"<kml xmlns:gx=\"http://www.google.com/kml/ext/2.2\"><Placemark>"
+ getNameAndDescription(TRACK_NAME_0, TRACK_DESCRIPTION_0) + "<gx:MultiTrack><gx:Track>"
+ getTrackPoint(0, TRACK_TIME_0) + getTrackPoint(1, TRACK_TIME_1) + "</gx:Track><gx:Track>"
+ getTrackPoint(2, TRACK_TIME_2) + getTrackPoint(3, TRACK_TIME_3)
+ "</gx:Track></gx:MultiTrack></Placemark></kml>";
/**
* Tests one track with one segment.
*/
public void testOneTrackOneSegment() throws Exception {
Capture<Track> track = new Capture<Track>();
Location location0 = createLocation(0, DATE_FORMAT_0.parse(TRACK_TIME_0).getTime());
Location location1 = createLocation(1, DATE_FORMAT_1.parse(TRACK_TIME_1).getTime());
expect(myTracksProviderUtils.insertTrack((Track) AndroidMock.anyObject()))
.andReturn(TRACK_ID_0_URI);
expectFirstTrackPoint(location0, TRACK_ID_0, TRACK_POINT_ID_0);
// A flush happens at the end
expect(myTracksProviderUtils.bulkInsertTrackPoint(
LocationsMatcher.eqLoc(location1), eq(1), eq(TRACK_ID_0))).andReturn(1);
expect(myTracksProviderUtils.getLastTrackPointId(TRACK_ID_0)).andReturn(TRACK_POINT_ID_1);
expectUpdateTrack(track, true, TRACK_ID_0);
AndroidMock.replay(myTracksProviderUtils);
InputStream inputStream = new ByteArrayInputStream(VALID_ONE_TRACK_ONE_SEGMENT_GPX.getBytes());
KmlImporter kmlImporter = new KmlImporter(getContext(), myTracksProviderUtils);
long[] trackIds = kmlImporter.importFile(inputStream);
assertEquals(1, trackIds.length);
assertEquals(TRACK_ID_0, trackIds[0]);
long time0 = DATE_FORMAT_0.parse(TRACK_TIME_0).getTime();
long time1 = DATE_FORMAT_1.parse(TRACK_TIME_1).getTime();
assertEquals(time1 - time0, track.getValue().getTripStatistics().getTotalTime());
AndroidMock.verify(myTracksProviderUtils);
verifyTrack(track.getValue(), TRACK_NAME_0, TRACK_DESCRIPTION_0, time0);
}
/**
* Tests one track with two segments.
*/
public void testOneTrackTwoSegments() throws Exception {
Capture<Track> track = new Capture<Track>();
Location location0 = createLocation(0, DATE_FORMAT_0.parse(TRACK_TIME_0).getTime());
expect(myTracksProviderUtils.insertTrack((Track) AndroidMock.anyObject()))
.andReturn(TRACK_ID_0_URI);
expectFirstTrackPoint(location0, TRACK_ID_0, TRACK_POINT_ID_0);
// A flush happens at the end
expect(myTracksProviderUtils.bulkInsertTrackPoint(
(Location[]) AndroidMock.anyObject(), eq(5), eq(TRACK_ID_0))).andStubReturn(5);
expect(myTracksProviderUtils.getLastTrackPointId(TRACK_ID_0)).andReturn(TRACK_POINT_ID_3);
expectUpdateTrack(track, true, TRACK_ID_0);
AndroidMock.replay(myTracksProviderUtils);
InputStream inputStream = new ByteArrayInputStream(VALID_ONE_TRACK_TWO_SEGMENTS_GPX.getBytes());
KmlImporter kmlImporter = new KmlImporter(getContext(), myTracksProviderUtils);
long[] trackIds = kmlImporter.importFile(inputStream);
assertEquals(1, trackIds.length);
assertEquals(TRACK_ID_0, trackIds[0]);
long time0 = DATE_FORMAT_0.parse(TRACK_TIME_0).getTime();
long time1 = DATE_FORMAT_1.parse(TRACK_TIME_1).getTime();
long time2 = DATE_FORMAT_1.parse(TRACK_TIME_2).getTime();
long time3 = DATE_FORMAT_1.parse(TRACK_TIME_3).getTime();
assertEquals(
time1 - time0 + time3 - time2, track.getValue().getTripStatistics().getTotalTime());
AndroidMock.verify(myTracksProviderUtils);
verifyTrack(track.getValue(), TRACK_NAME_0, TRACK_DESCRIPTION_0,
DATE_FORMAT_0.parse(TRACK_TIME_0).getTime());
}
}
@@ -0,0 +1,126 @@
/*
* Copyright 2010 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 com.google.android.apps.mytracks.io.file;
import com.google.android.apps.mytracks.content.DescriptionGenerator;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.stats.TripStatistics;
import android.location.Location;
import java.util.List;
import java.util.Vector;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Tests for {@link KmlTrackWriter}.
*
* @author Rodrigo Damazio
*/
public class KmlTrackWriterTest extends TrackFormatWriterTest {
private static final String FULL_TRACK_DESCRIPTION = "full track description";
/**
* A fake version of {@link DescriptionGenerator} which returns a fixed track
* description, thus not depending on the context.
*/
private class FakeDescriptionGenerator implements DescriptionGenerator {
@Override
public String generateTrackDescription(
Track aTrack, Vector<Double> distances, Vector<Double> elevations, boolean html) {
return FULL_TRACK_DESCRIPTION;
}
@Override
public String generateWaypointDescription(TripStatistics tripStatistics) {
return null;
}
}
public void testXmlOutput() throws Exception {
KmlTrackWriter writer = new KmlTrackWriter(getContext(), new FakeDescriptionGenerator());
String result = writeTrack(writer);
Document doc = parseXmlDocument(result);
Element kmlTag = getChildElement(doc, "kml");
Element docTag = getChildElement(kmlTag, "Document");
assertEquals(TRACK_NAME, getChildTextValue(docTag, "name"));
// There are 3 placemarks - start, track, and end
List<Element> placemarkTags = getChildElements(docTag, "Placemark", 3);
assertTagIsPlacemark(
placemarkTags.get(0), TRACK_NAME + " (Start)", "", location1);
assertTagIsPlacemark(
placemarkTags.get(2), TRACK_NAME + " (End)", FULL_TRACK_DESCRIPTION, location4);
List<Element> folderTag = getChildElements(docTag, "Folder", 1);
List<Element> folderPlacemarkTags = getChildElements(folderTag.get(0), "Placemark", 2);
assertTagIsPlacemark(
folderPlacemarkTags.get(0), WAYPOINT1_NAME, WAYPOINT1_DESCRIPTION, location2);
assertTagIsPlacemark(
folderPlacemarkTags.get(1), WAYPOINT2_NAME, WAYPOINT2_DESCRIPTION, location3);
Element trackPlacemarkTag = placemarkTags.get(1);
assertEquals(TRACK_NAME, getChildTextValue(trackPlacemarkTag, "name"));
assertEquals(TRACK_DESCRIPTION, getChildTextValue(trackPlacemarkTag, "description"));
Element multiTrackTag = getChildElement(trackPlacemarkTag, "gx:MultiTrack");
List<Element> trackTags = getChildElements(multiTrackTag, "gx:Track", 2);
assertTagHasPoints(trackTags.get(0), location1, location2);
assertTagHasPoints(trackTags.get(1), location3, location4);
}
/**
* Asserts that the given tag is a placemark with the given properties.
*
* @param tag the tag
* @param name the expected placemark name
* @param description the expected placemark description
* @param location the expected placemark location
*/
private void assertTagIsPlacemark(
Element tag, String name, String description, Location location) {
assertEquals(name, getChildTextValue(tag, "name"));
if (description != null && !description.equals("")) {
assertEquals(description, getChildTextValue(tag, "description"));
}
Element pointTag = getChildElement(tag, "Point");
String expected = location.getLongitude() + "," + location.getLatitude() + ","
+ location.getAltitude();
String actual = getChildTextValue(pointTag, "coordinates");
assertEquals(expected, actual);
}
/**
* Asserts that the given tag has a list of "gx:coord" subtags matching the
* expected locations.
*
* @param tag the parent tag
* @param locations list of expected locations
*/
private void assertTagHasPoints(Element tag, Location... locations) {
List<Element> coordTags = getChildElements(tag, "gx:coord", locations.length);
for (int i = 0; i < locations.length; i++) {
Location location = locations[i];
String expected = location.getLongitude() + " " + location.getLatitude() + " "
+ location.getAltitude();
String actual = coordTags.get(i).getFirstChild().getTextContent();
assertEquals(expected, actual);
}
}
}
@@ -0,0 +1,81 @@
/*
* 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 com.google.android.apps.mytracks.io.file;
import com.google.android.testing.mocking.AndroidMock;
import android.location.Location;
import java.util.Arrays;
import org.easymock.IArgumentMatcher;
/**
* Locations matcher. Workaround because of capture bug 2617107 in easymock:
* http://sourceforge.net/tracker/?func=detail&aid=2617107&group_id=82958&atid=567837
*
* @author Jimmy Shih
*/
public class LocationsMatcher implements IArgumentMatcher {
public static Location[] eqLoc(Location expected) {
return eqLoc(new Location[] { expected });
}
public static Location[] eqLoc(Location[] expected) {
IArgumentMatcher matcher = new LocationsMatcher(expected);
AndroidMock.reportMatcher(matcher);
return null;
}
private final Location[] expectedLocations;
private LocationsMatcher(Location[] expected) {
this.expectedLocations = expected;
}
@Override
public void appendTo(StringBuffer buf) {
buf.append("eqLoc(").append(Arrays.toString(expectedLocations)).append(")");
}
@Override
public boolean matches(Object obj) {
if (!(obj instanceof Location[])) {
return false;
}
Location[] locations = (Location[]) obj;
if (locations.length < expectedLocations.length) {
return false;
}
// Only check the first elements (those that will be taken into account)
for (int i = 0; i < expectedLocations.length; i++) {
if (!matchLocation(locations[i], expectedLocations[i])) {
return false;
}
}
return true;
}
private boolean matchLocation(Location location1, Location location2) {
return (location1.getTime() == location2.getTime())
&& (location1.getLatitude() == location2.getLatitude())
&& (location1.getLongitude() == location2.getLongitude())
&& (location1.getAltitude() == location2.getAltitude());
}
}
@@ -0,0 +1,96 @@
/*
* Copyright 2010 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 com.google.android.apps.mytracks.io.file;
import com.google.android.apps.mytracks.content.MyTracksLocation;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.util.StringUtils;
import java.util.List;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Tests for {@link TcxTrackWriter}.
*
* @author Sandor Dornbush
*/
public class TcxTrackWriterTest extends TrackFormatWriterTest {
public void testXmlOutput() throws Exception {
TrackFormatWriter writer = new TcxTrackWriter(getContext());
String result = writeTrack(writer);
Document doc = parseXmlDocument(result);
Element root = getChildElement(doc, "TrainingCenterDatabase");
Element activitiesTag = getChildElement(root, "Activities");
Element activityTag = getChildElement(activitiesTag, "Activity");
Element lapTag = getChildElement(activityTag, "Lap");
List<Element> segmentTags = getChildElements(lapTag, "Track", 2);
Element segment1Tag = segmentTags.get(0);
Element segment2Tag = segmentTags.get(1);
List<Element> seg1PointTags = getChildElements(segment1Tag, "Trackpoint", 2);
List<Element> seg2PointTags = getChildElements(segment2Tag, "Trackpoint", 2);
assertTagsMatchPoints(seg1PointTags, location1, location2);
assertTagsMatchPoints(seg2PointTags, location3, location4);
}
/**
* Asserts that the given tags describe the given locations in the same order.
*
* @param tags list of tags
* @param locations list of locations
*/
private void assertTagsMatchPoints(List<Element> tags, MyTracksLocation... locations) {
assertEquals(locations.length, tags.size());
for (int i = 0; i < locations.length; i++) {
assertTagMatchesLocation(tags.get(i), locations[i]);
}
}
/**
* Asserts that the given tag describes the given location.
*
* @param tag the tag
* @param location the location
*/
private void assertTagMatchesLocation(Element tag, MyTracksLocation location) {
assertEquals(StringUtils.formatDateTimeIso8601(location.getTime()), getChildTextValue(tag, "Time"));
Element positionTag = getChildElement(tag, "Position");
assertEquals(
Double.toString(location.getLatitude()), getChildTextValue(positionTag, "LatitudeDegrees"));
assertEquals(Double.toString(location.getLongitude()),
getChildTextValue(positionTag, "LongitudeDegrees"));
assertEquals(Double.toString(location.getAltitude()), getChildTextValue(tag, "AltitudeMeters"));
assertTrue(location.getSensorDataSet() != null);
Sensor.SensorDataSet sds = location.getSensorDataSet();
List<Element> heartRate = getChildElements(tag, "HeartRateBpm", 1);
assertEquals(Integer.toString(sds.getHeartRate().getValue()),
getChildTextValue(heartRate.get(0), "Value"));
List<Element> extensions = getChildElements(tag, "Extensions", 1);
List<Element> tpx = getChildElements(extensions.get(0), "TPX", 1);
assertEquals(
Integer.toString(sds.getCadence().getValue()), getChildTextValue(tpx.get(0), "RunCadence"));
assertEquals(
Integer.toString(sds.getPower().getValue()), getChildTextValue(tpx.get(0), "Watts"));
}
}
@@ -0,0 +1,217 @@
// Copyright 2010 Google Inc. All Rights Reserved.
package com.google.android.apps.mytracks.io.file;
import com.google.android.apps.mytracks.content.MyTracksLocation;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import android.test.AndroidTestCase;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* Base class for track format writer tests, which sets up a fake track and
* gives auxiliary methods for verifying XML output.
*
* @author Rodrigo Damazio
*/
public abstract class TrackFormatWriterTest extends AndroidTestCase {
// All the user-provided strings have "]]>" to ensure that proper escaping is
// being done.
protected static final String TRACK_NAME = "Home]]>";
protected static final String TRACK_CATEGORY = "Hiking";
protected static final String TRACK_DESCRIPTION = "The long ]]> journey home";
protected static final String WAYPOINT1_NAME = "point]]>1";
protected static final String WAYPOINT1_CATEGORY = "Statistics";
protected static final String WAYPOINT1_DESCRIPTION = "point 1]]>description";
protected static final String WAYPOINT2_NAME = "point]]>2";
protected static final String WAYPOINT2_CATEGORY = "Waypoint";
protected static final String WAYPOINT2_DESCRIPTION = "point 2]]>description";
private static final int BUFFER_SIZE = 10240;
protected Track track;
protected MyTracksLocation location1, location2, location3, location4;
protected Waypoint wp1, wp2;
@Override
protected void setUp() throws Exception {
super.setUp();
track = new Track();
track.setName(TRACK_NAME);
track.setCategory(TRACK_CATEGORY);
track.setDescription(TRACK_DESCRIPTION);
location1 = new MyTracksLocation("mock");
location2 = new MyTracksLocation("mock");
location3 = new MyTracksLocation("mock");
location4 = new MyTracksLocation("mock");
populateLocations(location1, location2, location3, location4);
wp1 = new Waypoint();
wp2 = new Waypoint();
wp1.setLocation(location2);
wp1.setName(WAYPOINT1_NAME);
wp1.setCategory(WAYPOINT1_CATEGORY);
wp1.setDescription(WAYPOINT1_DESCRIPTION);
wp2.setLocation(location3);
wp2.setName(WAYPOINT2_NAME);
wp2.setCategory(WAYPOINT2_CATEGORY);
wp2.setDescription(WAYPOINT2_DESCRIPTION);
}
/**
* Populates a list of locations with values.
*
* @param locations a list of locations
*/
private void populateLocations(MyTracksLocation... locations) {
for (int i = 0; i < locations.length; i++) {
MyTracksLocation location = locations[i];
location.setLatitude(i);
location.setLongitude(-i);
location.setAltitude(i * 10);
location.setBearing(i * 100);
location.setAccuracy(i * 1000);
location.setSpeed(i * 10000);
location.setTime(i * 100000);
Sensor.SensorData.Builder power = Sensor.SensorData.newBuilder().setValue(100 + i)
.setState(Sensor.SensorState.SENDING);
Sensor.SensorData.Builder cadence = Sensor.SensorData.newBuilder().setValue(200 + i)
.setState(Sensor.SensorState.SENDING);
Sensor.SensorData.Builder heartRate = Sensor.SensorData.newBuilder().setValue(300 + i)
.setState(Sensor.SensorState.SENDING);
Sensor.SensorDataSet sensorDataSet = Sensor.SensorDataSet.newBuilder().setPower(power)
.setCadence(cadence).setHeartRate(heartRate).build();
location.setSensorDataSet(sensorDataSet);
}
}
/**
* Makes the right sequence of calls to the writer in order to write the fake
* track in {@link #track}.
*
* @param writer the writer to write to
* @return the written contents
*/
protected String writeTrack(TrackFormatWriter writer) throws Exception {
OutputStream output = new ByteArrayOutputStream(BUFFER_SIZE);
writer.prepare(output);
writer.writeHeader(track);
writer.writeBeginWaypoints();
writer.writeWaypoint(wp1);
writer.writeWaypoint(wp2);
writer.writeEndWaypoints();
writer.writeBeginTrack(track, location1);
writer.writeOpenSegment();
writer.writeLocation(location1);
writer.writeLocation(location2);
writer.writeCloseSegment();
writer.writeOpenSegment();
writer.writeLocation(location3);
writer.writeLocation(location4);
writer.writeCloseSegment();
writer.writeEndTrack(track, location4);
writer.writeFooter();
writer.close();
return output.toString();
}
/**
* Gets the text data contained inside a tag.
*
* @param parent the parent of the tag containing the text
* @param elementName the name of the tag containing the text
* @return the text contents
*/
protected String getChildTextValue(Element parent, String elementName) {
Element child = getChildElement(parent, elementName);
assertTrue(child.hasChildNodes());
NodeList children = child.getChildNodes();
int length = children.getLength();
assertTrue(length > 0);
// The children may be a sucession of text elements, just concatenate them
String result = "";
for (int i = 0; i < length; i++) {
Text textNode = (Text) children.item(i);
result += textNode.getNodeValue();
}
return result;
}
/**
* Returns all child elements of a given parent which have the given name.
*
* @param parent the parent to get children from
* @param elementName the element name to look for
* @param expectedChildren the number of children we're expected to find
* @return a list of the found elements
*/
protected List<Element> getChildElements(Node parent, String elementName,
int expectedChildren) {
assertTrue(parent.hasChildNodes());
NodeList children = parent.getChildNodes();
int length = children.getLength();
List<Element> result = new ArrayList<Element>();
for (int i = 0; i < length; i++) {
Node childNode = children.item(i);
if (childNode.getNodeType() == Node.ELEMENT_NODE
&& childNode.getNodeName().equalsIgnoreCase(elementName)) {
result.add((Element) childNode);
}
}
assertTrue(children.toString(), result.size() == expectedChildren);
return result;
}
/**
* Returns the single child element of the given parent with the given type.
*
* @param parent the parent to get a child from
* @param elementName the name of the child to look for
* @return the child element
*/
protected Element getChildElement(Node parent, String elementName) {
return getChildElements(parent, elementName, 1).get(0);
}
/**
* Parses the given XML contents and returns a DOM {@link Document} for it.
*/
protected Document parseXmlDocument(String contents)
throws FactoryConfigurationError, ParserConfigurationException,
SAXException, IOException {
DocumentBuilderFactory builderFactory =
DocumentBuilderFactory.newInstance();
builderFactory.setCoalescing(true);
// TODO: Somehow do XML validation on Android
// builderFactory.setValidating(true);
builderFactory.setNamespaceAware(true);
builderFactory.setIgnoringComments(true);
builderFactory.setIgnoringElementContentWhitespace(true);
DocumentBuilder documentBuilder = builderFactory.newDocumentBuilder();
Document doc = documentBuilder.parse(
new InputSource(new StringReader(contents)));
return doc;
}
}
@@ -0,0 +1,310 @@
// Copyright 2010 Google Inc. All Rights Reserved.
package com.google.android.apps.mytracks.io.file;
import com.google.android.apps.mytracks.content.MyTracksProvider;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.Factory;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.io.file.TrackWriter.OnWriteListener;
import com.google.android.apps.mytracks.services.TrackRecordingServiceTest.MockContext;
import com.google.android.apps.mytracks.testing.TestingProviderUtilsFactory;
import android.content.Context;
import android.location.Location;
import android.test.AndroidTestCase;
import android.test.RenamingDelegatingContext;
import android.test.mock.MockContentResolver;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import org.easymock.EasyMock;
import org.easymock.IArgumentMatcher;
import org.easymock.IMocksControl;
/**
* Tests for {@link TrackWriter}.
*
* @author Rodrigo Damazio
*/
public class TrackWriterTest extends AndroidTestCase {
private static final long TRACK_ID = 1234567L;
private static final String TRACK_NAME = "Swimming across the pacific";
private MyTracksProviderUtils myTracksProviderUtils;
private Factory oldProviderUtilsFactory;
private IMocksControl mocksControl;
private TrackFormatWriter trackFormatWriter;
private Track track;
private OutputStream outputStream;
private TrackWriter trackWriter;
@Override
protected void setUp() throws Exception {
super.setUp();
MockContentResolver mockContentResolver = new MockContentResolver();
RenamingDelegatingContext targetContext = new RenamingDelegatingContext(
getContext(), getContext(), "test.");
Context context = new MockContext(mockContentResolver, targetContext);
MyTracksProvider myTracksProvider = new MyTracksProvider();
myTracksProvider.attachInfo(context, null);
mockContentResolver.addProvider(MyTracksProviderUtils.AUTHORITY, myTracksProvider);
setContext(context);
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context);
oldProviderUtilsFactory = TestingProviderUtilsFactory.installWithInstance(
myTracksProviderUtils);
mocksControl = EasyMock.createStrictControl();
trackFormatWriter = mocksControl.createMock(TrackFormatWriter.class);
track = new Track();
track.setName(TRACK_NAME);
track.setId(TRACK_ID);
outputStream = new ByteArrayOutputStream();
OnWriteListener onWriteListener = new OnWriteListener() {
@Override
public void onWrite(int number, int max) {
// Safe to ignore
}
};
trackWriter = new TrackWriter(myTracksProviderUtils, new Track[] {track}, trackFormatWriter, onWriteListener);
}
@Override
protected void tearDown() throws Exception {
TestingProviderUtilsFactory.restoreOldFactory(oldProviderUtilsFactory);
super.tearDown();
}
/**
* Tests write track with an empty track.
*/
public void testWriteTrack_emptyTrack() throws Exception {
// Set expected mock behavior
trackFormatWriter.prepare(outputStream);
trackFormatWriter.writeHeader(track);
trackFormatWriter.writeBeginTrack(track, null);
trackFormatWriter.writeEndTrack(track, null);
trackFormatWriter.writeFooter();
trackFormatWriter.close();
mocksControl.replay();
trackWriter.writeTrack(outputStream);
assertTrue(trackWriter.wasSuccess());
mocksControl.verify();
}
/**
* Tests write track with invalid locations. Make sure an empty track is
* written.
*/
public void testWriteTrack_oneInvalidLocation() throws Exception {
// Add two locations
Location[] locations = { new Location("fake0"), new Location("fake1") };
fillLocations(locations);
// Make locations invalid
locations[0].setLatitude(100.0);
locations[1].setLatitude(100.0);
assertEquals(locations.length,
myTracksProviderUtils.bulkInsertTrackPoint(locations, locations.length, TRACK_ID));
// Set expected mock behavior
trackFormatWriter.prepare(outputStream);
trackFormatWriter.writeHeader(track);
trackFormatWriter.writeBeginTrack(track, null);
trackFormatWriter.writeEndTrack(track, null);
trackFormatWriter.writeFooter();
trackFormatWriter.close();
mocksControl.replay();
trackWriter.writeTrack(outputStream);
assertTrue(trackWriter.wasSuccess());
mocksControl.verify();
}
/**
* Tests write track.
*/
public void testWriteTrack() throws Exception {
// Add six locations
Location[] locations = { new Location("fake0"), new Location("fake1"), new Location("fake2"),
new Location("fake3"), new Location("fake4"), new Location("fake5") };
fillLocations(locations);
// Make location 3 invalid
locations[2].setLatitude(100.0);
assertEquals(locations.length,
myTracksProviderUtils.bulkInsertTrackPoint(locations, locations.length, TRACK_ID));
Waypoint[] waypoints = { new Waypoint(), new Waypoint(), new Waypoint() };
for (int i = 0; i < waypoints.length; i++) {
Waypoint waypoint = waypoints[i];
waypoint.setTrackId(TRACK_ID);
assertNotNull(myTracksProviderUtils.insertWaypoint(waypoint));
waypoint.setId(i + 1);
}
trackFormatWriter.prepare(outputStream);
trackFormatWriter.writeHeader(track);
// Expect reading/writing of the waypoints (except the first)
trackFormatWriter.writeBeginWaypoints();
trackFormatWriter.writeWaypoint(waypointEq(waypoints[1]));
trackFormatWriter.writeWaypoint(waypointEq(waypoints[2]));
trackFormatWriter.writeEndWaypoints();
// Begin the track
trackFormatWriter.writeBeginTrack(trackEq(track), locationEq(locations[0]));
// Write locations 1-2
trackFormatWriter.writeOpenSegment();
trackFormatWriter.writeLocation(locationEq(locations[0]));
trackFormatWriter.writeLocation(locationEq(locations[1]));
trackFormatWriter.writeCloseSegment();
// Location 3 is not written - it's invalid
// Write locations 4-6
trackFormatWriter.writeOpenSegment();
trackFormatWriter.writeLocation(locationEq(locations[3]));
trackFormatWriter.writeLocation(locationEq(locations[4]));
trackFormatWriter.writeLocation(locationEq(locations[5]));
trackFormatWriter.writeCloseSegment();
// End the track
trackFormatWriter.writeEndTrack(trackEq(track), locationEq(locations[5]));
trackFormatWriter.writeFooter();
trackFormatWriter.close();
mocksControl.replay();
trackWriter.writeTrack(outputStream);
assertTrue(trackWriter.wasSuccess());
mocksControl.verify();
}
/**
* Waypoint equals.
*
* @param waypoint the waypoint
*/
private Waypoint waypointEq(final Waypoint waypoint) {
EasyMock.reportMatcher(new IArgumentMatcher() {
@Override
public boolean matches(Object object) {
if (object == null || waypoint == null) {
return waypoint == object;
}
Waypoint waypoint2 = (Waypoint) object;
return waypoint.getId() == waypoint2.getId();
}
@Override
public void appendTo(StringBuffer buffer) {
buffer.append("waypointEq(");
buffer.append(waypoint);
buffer.append(")");
}
});
return null;
}
/**
* Location equals.
*
* @param location the location
*/
private Location locationEq(final Location location) {
EasyMock.reportMatcher(new IArgumentMatcher() {
@Override
public boolean matches(Object object) {
if (object == null || location == null) {
return location == object;
}
Location location2 = (Location) object;
return location.hasAccuracy() == location2.hasAccuracy()
&& (!location.hasAccuracy() || location.getAccuracy() == location2.getAccuracy())
&& location.hasAltitude() == location2.hasAltitude()
&& (!location.hasAltitude() || location.getAltitude() == location2.getAltitude())
&& location.hasBearing() == location2.hasBearing()
&& (!location.hasBearing() || location.getBearing() == location2.getBearing())
&& location.hasSpeed() == location2.hasSpeed()
&& (!location.hasSpeed() || location.getSpeed() == location2.getSpeed())
&& location.getLatitude() == location2.getLatitude()
&& location.getLongitude() == location2.getLongitude()
&& location.getTime() == location2.getTime();
}
@Override
public void appendTo(StringBuffer buffer) {
buffer.append("locationEq(");
buffer.append(location);
buffer.append(")");
}
});
return null;
}
/**
* Track equals.
*
* @param track1 the track
*/
private Track trackEq(final Track track1) {
EasyMock.reportMatcher(new IArgumentMatcher() {
@Override
public boolean matches(Object object) {
if (object == null || track1 == null) {
return track1 == object;
}
Track track2 = (Track) object;
return track1.getName().equals(track2.getName());
}
@Override
public void appendTo(StringBuffer buffer) {
buffer.append("trackEq(");
buffer.append(track1);
buffer.append(")");
}
});
return null;
}
/**
* Fills the locations.
*
* @param locations the locations
*/
private void fillLocations(Location... locations) {
assertTrue(locations.length < 90);
for (int i = 0; i < locations.length; i++) {
Location location = locations[i];
location.setLatitude(i + 1);
location.setLongitude(i + 1);
location.setTime(i + 1000);
}
}
}
@@ -0,0 +1,85 @@
/*
* 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 com.google.android.apps.mytracks.io.fusiontables;
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
import com.google.android.apps.mytracks.io.sendtogoogle.UploadResultActivity;
import com.google.android.apps.mytracks.io.spreadsheets.SendSpreadsheetsActivity;
import android.test.AndroidTestCase;
/**
* Tests the {@link SendFusionTablesActivity}.
*
* @author Youtao Liu
*/
public class SendFusionTablesActivityTest extends AndroidTestCase {
private SendFusionTablesActivity sendFusionTablesActivity;
private SendRequest sendRequest;
@Override
protected void setUp() throws Exception {
super.setUp();
sendRequest = new SendRequest(1L);
sendFusionTablesActivity = new SendFusionTablesActivity();
}
/**
* Tests the method
* {@link SendFusionTablesActivity#getNextClass(SendRequest, boolean)}. Sets
* the flags of "sendSpreadsheets" and "cancel" to false and false.
*/
public void testGetNextClass_notCancelNotSendSpreadsheets() {
sendRequest.setSendSpreadsheets(false);
Class<?> next = sendFusionTablesActivity.getNextClass(sendRequest, false);
assertEquals(UploadResultActivity.class, next);
}
/**
* Tests the method
* {@link SendFusionTablesActivity#getNextClass(SendRequest, boolean)}. Sets
* the flags of "sendSpreadsheets" and "cancel" to true and false.
*/
public void testGetNextClass_notCancelSendSpreadsheets() {
sendRequest.setSendSpreadsheets(true);
Class<?> next = sendFusionTablesActivity.getNextClass(sendRequest, false);
assertEquals(SendSpreadsheetsActivity.class, next);
}
/**
* Tests the method
* {@link SendFusionTablesActivity#getNextClass(SendRequest,boolean)}. Sets
* the flags of "sendSpreadsheets" and "cancel" to true and true.
*/
public void testGetNextClass_cancelSendSpreadsheets() {
sendRequest.setSendSpreadsheets(true);
Class<?> next = sendFusionTablesActivity.getNextClass(sendRequest, true);
assertEquals(UploadResultActivity.class, next);
}
/**
* Tests the method
* {@link SendFusionTablesActivity#getNextClass(SendRequest,boolean)}. Sets
* the flags of "sendSpreadsheets" and "cancel" to false and true.
*/
public void testGetNextClass_cancelNotSendSpreadsheets() {
sendRequest.setSendSpreadsheets(false);
Class<?> next = sendFusionTablesActivity.getNextClass(sendRequest, true);
assertEquals(UploadResultActivity.class, next);
}
}
@@ -0,0 +1,226 @@
/*
* 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 com.google.android.apps.mytracks.io.fusiontables;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.stats.TripStatistics;
import android.location.Location;
import java.util.ArrayList;
import junit.framework.TestCase;
/**
* Tests {@link SendFusionTablesUtils}.
*
* @author Jimmy Shih
*/
public class SendFusionTablesUtilsTest extends TestCase {
/**
* Tests {@link SendFusionTablesUtils#getMapUrl(Track)} with null track.
*/
public void testGetMapUrl_null_track() {
assertEquals(null, SendFusionTablesUtils.getMapUrl(null));
}
/**
* Tests {@link SendFusionTablesUtils#getMapUrl(Track)} with null table id.
*/
public void testGetMapUrl_null_table_id() {
Track track = new Track();
TripStatistics stats = new TripStatistics();
stats.setBounds((int) 100.E6, (int) 10.E6, (int) 50.E6, (int) 5.E6);
track.setTripStatistics(stats);
track.setTableId(null);
assertEquals(null, SendFusionTablesUtils.getMapUrl(track));
}
/**
* Tests {@link SendFusionTablesUtils#getMapUrl(Track)} with null stats.
*/
public void testGetMapUrl_null_stats() {
Track track = new Track();
track.setTripStatistics(null);
track.setTableId("123");
assertEquals(null, SendFusionTablesUtils.getMapUrl(track));
}
/**
* Tests {@link SendFusionTablesUtils#getMapUrl(Track)} with a valid track.
*/
public void testGetMapUrl_valid_track() {
Track track = new Track();
track.setNumberOfPoints(2);
TripStatistics stats = new TripStatistics();
stats.setBounds((int) 100.E6, (int) 10.E6, (int) 50.E6, (int) 5.E6);
track.setTripStatistics(stats);
track.setTableId("123");
assertEquals(
"https://www.google.com/fusiontables/embedviz?"
+ "viz=MAP&q=select+col0,+col1,+col2,+col3+from+123+&h=false&lat=7.500000&lng=75.000000"
+ "&z=15&t=1&l=col2", SendFusionTablesUtils.getMapUrl(track));
}
/**
* Tests (@link {@link SendFusionTablesUtils#formatSqlValues(String...)} with
* no value.
*/
public void testFormatSqlValues_no_value() {
assertEquals("()", SendFusionTablesUtils.formatSqlValues());
}
/**
* Tests (@link {@link SendFusionTablesUtils#formatSqlValues(String...)} with
* an empty string.
*/
public void testFormatSqlValues_empty_string() {
assertEquals("(\'\')", SendFusionTablesUtils.formatSqlValues(""));
}
/**
* Tests (@link {@link SendFusionTablesUtils#formatSqlValues(String...)} with
* one value.
*/
public void testFormatSqlValues_one_value() {
assertEquals("(\'first\')", SendFusionTablesUtils.formatSqlValues("first"));
}
/**
* Tests (@link {@link SendFusionTablesUtils#formatSqlValues(String...)} with
* two values.
*/
public void testFormatSqlValues_two_values() {
assertEquals(
"(\'first\',\'second\')", SendFusionTablesUtils.formatSqlValues("first", "second"));
}
/**
* Tests {@link SendFusionTablesUtils#escapeSqlString(String)} with a value
* containing several single quotes.
*/
public void testEscapeSqValuel() {
String value = "let's'";
assertEquals("let''s''", SendFusionTablesUtils.escapeSqlString(value));
}
/**
* Tests {@link SendFusionTablesUtils#getKmlPoint(Location)} with a null
* point.
*/
public void testGetKmlPoint_null_point() {
assertEquals(
"<Point><coordinates></coordinates></Point>", SendFusionTablesUtils.getKmlPoint(null));
}
/**
* Tests {@link SendFusionTablesUtils#getKmlPoint(Location)} with a valid
* point.
*/
public void testGetKmlPoint_valid_point() {
Location location = new Location("test");
location.setLongitude(10.1);
location.setLatitude(20.2);
location.setAltitude(30.3);
assertEquals("<Point><coordinates>10.1,20.2,30.3</coordinates></Point>",
SendFusionTablesUtils.getKmlPoint(location));
}
/**
* Tests {@link SendFusionTablesUtils#getKmlLineString(ArrayList)} with a null
* locations.
*/
public void testKmlLineString_null_locations() {
assertEquals("<LineString><coordinates></coordinates></LineString>",
SendFusionTablesUtils.getKmlLineString(null));
}
/**
* Tests {@link SendFusionTablesUtils#getKmlLineString(ArrayList)} with no
* location.
*/
public void testKmlLineString_no_location() {
ArrayList<Location> locations = new ArrayList<Location>();
assertEquals("<LineString><coordinates></coordinates></LineString>",
SendFusionTablesUtils.getKmlLineString(locations));
}
/**
* Tests {@link SendFusionTablesUtils#getKmlLineString(ArrayList)} with one
* location.
*/
public void testKmlLineString_one_location() {
ArrayList<Location> locations = new ArrayList<Location>();
Location location = new Location("test");
location.setLongitude(10.1);
location.setLatitude(20.2);
location.setAltitude(30.3);
locations.add(location);
assertEquals("<LineString><coordinates>10.1,20.2,30.3</coordinates></LineString>",
SendFusionTablesUtils.getKmlLineString(locations));
}
/**
* Tests {@link SendFusionTablesUtils#getKmlLineString(ArrayList)} with two
* locations.
*/
public void testKmlLineString_two_locations() {
ArrayList<Location> locations = new ArrayList<Location>();
Location location1 = new Location("test");
location1.setLongitude(10.1);
location1.setLatitude(20.2);
location1.setAltitude(30.3);
locations.add(location1);
Location location2 = new Location("test");
location2.setLongitude(1.1);
location2.setLatitude(2.2);
location2.removeAltitude();
locations.add(location2);
assertEquals("<LineString><coordinates>10.1,20.2,30.3 1.1,2.2</coordinates></LineString>",
SendFusionTablesUtils.getKmlLineString(locations));
}
/**
* Tests {@link SendFusionTablesUtils#appendLocation(Location, StringBuilder)}
* with no altitude.
*/
public void testAppendLocation_no_altitude() {
StringBuilder builder = new StringBuilder();
Location location = new Location("test");
location.setLongitude(10.1);
location.setLatitude(20.2);
location.removeAltitude();
SendFusionTablesUtils.appendLocation(location, builder);
assertEquals("10.1,20.2", builder.toString());
}
/**
* Tests {@link SendFusionTablesUtils#appendLocation(Location, StringBuilder)}
* with altitude.
*/
public void testAppendLocation_has_altitude() {
StringBuilder builder = new StringBuilder();
Location location = new Location("test");
location.setLongitude(10.1);
location.setLatitude(20.2);
location.setAltitude(30.3);
SendFusionTablesUtils.appendLocation(location, builder);
assertEquals("10.1,20.2,30.3", builder.toString());
}
}
@@ -0,0 +1,90 @@
/*
* 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 com.google.android.apps.mytracks.io.maps;
import com.google.android.apps.mytracks.io.fusiontables.SendFusionTablesActivity;
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
import com.google.android.apps.mytracks.io.sendtogoogle.UploadResultActivity;
import com.google.android.apps.mytracks.io.spreadsheets.SendSpreadsheetsActivity;
import android.test.AndroidTestCase;
/**
* Tests the {@link SendMapsActivity}.
*
* @author Youtao Liu
*/
public class SendMapsActivityTest extends AndroidTestCase {
private SendMapsActivity sendMapsActivity;
private SendRequest sendRequest;
@Override
protected void setUp() throws Exception {
super.setUp();
sendRequest = new SendRequest(1L);
sendMapsActivity = new SendMapsActivity();
}
/**
* Tests the method
* {@link SendMapsActivity#getNextClass(SendRequest, boolean)}. Sets the flags
* of "sendFusionTables","sendSpreadsheets" and "cancel" to true, true and false.
*/
public void testGetNextClass_notCancelSendFusionTables() {
sendRequest.setSendFusionTables(true);
sendRequest.setSendSpreadsheets(true);
Class<?> next = sendMapsActivity.getNextClass(sendRequest, false);
assertEquals(SendFusionTablesActivity.class, next);
}
/**
* Tests the method
* {@link SendMapsActivity#getNextClass(SendRequest, boolean)}. Sets the flags
* of "sendFusionTables","sendSpreadsheets" and "cancel" to false, true and false.
*/
public void testGetNextClass_notCancelSendSpreadsheets() {
sendRequest.setSendFusionTables(false);
sendRequest.setSendSpreadsheets(true);
Class<?> next = sendMapsActivity.getNextClass(sendRequest, false);
assertEquals(SendSpreadsheetsActivity.class, next);
}
/**
* Tests the method
* {@link SendMapsActivity#getNextClass(SendRequest, boolean)}. Sets the flags
* of "sendFusionTables","sendSpreadsheets" and "cancel" to false, false and false.
*/
public void testGetNextClass_notCancelNotSend() {
sendRequest.setSendFusionTables(false);
sendRequest.setSendSpreadsheets(false);
Class<?> next = sendMapsActivity.getNextClass(sendRequest, false);
assertEquals(UploadResultActivity.class, next);
}
/**
* Tests the method
* {@link SendMapsActivity#getNextClass(SendRequest, boolean)}. Sets the flags
* of "sendFusionTables","sendSpreadsheets" and "cancel" to true, true and true.
*/
public void testGetNextClass_cancelSendSpreadsheets() {
sendRequest.setSendFusionTables(true);
sendRequest.setSendSpreadsheets(true);
Class<?> next = sendMapsActivity.getNextClass(sendRequest, true);
assertEquals(UploadResultActivity.class, next);
}
}
@@ -0,0 +1,339 @@
/*
* 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 com.google.android.apps.mytracks.io.maps;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.TrackStubUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.io.gdata.maps.MapsGDataConverter;
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
import com.google.android.testing.mocking.AndroidMock;
import com.google.android.testing.mocking.UsesMocks;
import android.accounts.Account;
import android.database.Cursor;
import android.location.Location;
import android.test.AndroidTestCase;
import java.util.List;
import org.xmlpull.v1.XmlPullParserException;
/**
* Tests {@link SendMapsAsyncTask}.
*
* @author Youtao Liu
*/
public class SendMapsAsyncTaskTest extends AndroidTestCase {
private static final long TRACK_ID = 1;
// Records the run times of {@link SendMapsAsyncTaskMock#uploadMarker(String,
// String, String, Location)}
private int uploadMarkerCounter = 0;
// Records the run times of {@link
// SendMapsAsyncTaskMock#prepareAndUploadPoints(Track, List<Location>,
// boolean)}
private int prepareAndUploadPointsCounter = 0;
private SendMapsActivity sendMapsActivityMock;
private MyTracksProviderUtils myTracksProviderUtilsMock;
private SendRequest sendRequest;
private class SendMapsAsyncTaskMock extends SendMapsAsyncTask {
private boolean[] uploadMarkerResult = { false, false };
private boolean prepareAndUploadPointsResult = false;
private SendMapsAsyncTaskMock(SendMapsActivity activity, long trackId, Account account,
MyTracksProviderUtils myTracksProviderUtils) {
super(activity, trackId, account, myTracksProviderUtils);
}
@Override
boolean uploadMarker(String title, String description, String iconUrl, Location location) {
int runTimes = uploadMarkerCounter++;
return uploadMarkerResult[runTimes];
}
@Override
boolean prepareAndUploadPoints(Track track, List<Location> locations, boolean lastBatch) {
prepareAndUploadPointsCounter++;
return prepareAndUploadPointsResult;
}
}
@Override
@UsesMocks({ SendMapsActivity.class, MyTracksProviderUtils.class })
protected void setUp() throws Exception {
super.setUp();
uploadMarkerCounter = 0;
prepareAndUploadPointsCounter = 0;
sendMapsActivityMock = AndroidMock.createMock(SendMapsActivity.class);
myTracksProviderUtilsMock = AndroidMock.createMock(MyTracksProviderUtils.class);
sendRequest = new SendRequest(TRACK_ID);
AndroidMock.expect(sendMapsActivityMock.getApplicationContext()).andReturn(getContext());
}
/**
* Tests the method {@link SendMapsAsyncTask#saveResult()}and makes sure the
* track is updated.
*/
public void testSaveResult() {
Track track = TrackStubUtils.createTrack(1);
track.setMapId(null);
AndroidMock.expect(myTracksProviderUtilsMock.getTrack(TRACK_ID)).andReturn(track);
myTracksProviderUtilsMock.updateTrack(track);
AndroidMock.replay(sendMapsActivityMock, myTracksProviderUtilsMock);
SendMapsAsyncTask sendMapsAsyncTask = new SendMapsAsyncTask(sendMapsActivityMock,
sendRequest.getTrackId(), sendRequest.getAccount(), myTracksProviderUtilsMock);
sendMapsAsyncTask.saveResult();
AndroidMock.verify(sendMapsActivityMock, myTracksProviderUtilsMock);
}
/**
* Tests {@link SendMapsAsyncTask#fetchSendMapId(Track)} when chooseMapId is
* null and makes sure it returns false.
*/
public void testFetchSendMapId_nullMapID() {
Track track = TrackStubUtils.createTrack(1);
AndroidMock.replay(sendMapsActivityMock, myTracksProviderUtilsMock);
// Makes chooseMapId to null.
SendMapsAsyncTask sendMapsAsyncTask = new SendMapsAsyncTask(sendMapsActivityMock,
sendRequest.getTrackId(), sendRequest.getAccount(), myTracksProviderUtilsMock);
// Returns false for an exception would be thrown.
assertFalse(sendMapsAsyncTask.fetchSendMapId(track));
AndroidMock.verify(sendMapsActivityMock, myTracksProviderUtilsMock);
}
/**
* Tests the method {@link SendMapsAsyncTask#uploadAllTrackPoints(Track)} when
* cursor is null. And makes sure it returns false.
*/
public void testUploadAllTrackPoints_nullCursor() {
Track track = TrackStubUtils.createTrack(1);
AndroidMock.expect(myTracksProviderUtilsMock.getTrackPointCursor(TRACK_ID, -1L, -1, false))
.andReturn(null);
AndroidMock.replay(sendMapsActivityMock, myTracksProviderUtilsMock);
SendMapsAsyncTask sendMapsAsyncTask = new SendMapsAsyncTask(sendMapsActivityMock,
sendRequest.getTrackId(), sendRequest.getAccount(), myTracksProviderUtilsMock);
assertFalse(sendMapsAsyncTask.uploadAllTrackPoints(track));
AndroidMock.verify(sendMapsActivityMock, myTracksProviderUtilsMock);
}
/**
* Tests the method {@link SendMapsAsyncTask#uploadAllTrackPoints(Track)} when
* uploads the first marker is failed.
*/
@UsesMocks(Cursor.class)
public void testUploadAllTrackPoints_uploadFirstMarkerFailed() {
Track track = TrackStubUtils.createTrack(1);
Cursor cursorMock = AndroidMock.createMock(Cursor.class);
AndroidMock.expect(cursorMock.getCount()).andReturn(2);
AndroidMock.expect(cursorMock.moveToPosition(0)).andReturn(true);
cursorMock.close();
AndroidMock.expect(myTracksProviderUtilsMock.createTrackPoint(cursorMock)).andReturn(
new Location("1"));
AndroidMock.expect(myTracksProviderUtilsMock.getTrackPointCursor(TRACK_ID, -1L, -1, false))
.andReturn(cursorMock);
AndroidMock.replay(sendMapsActivityMock, myTracksProviderUtilsMock, cursorMock);
SendMapsAsyncTaskMock sendMapsAsyncTask = new SendMapsAsyncTaskMock(sendMapsActivityMock,
sendRequest.getTrackId(), sendRequest.getAccount(), myTracksProviderUtilsMock);
sendMapsAsyncTask.uploadMarkerResult[0] = false;
assertFalse(sendMapsAsyncTask.uploadAllTrackPoints(track));
assertEquals(1, uploadMarkerCounter);
AndroidMock.verify(sendMapsActivityMock, myTracksProviderUtilsMock, cursorMock);
}
/**
* Tests the method {@link SendMapsAsyncTask#uploadAllTrackPoints(Track)} when
* uploads the two markers is successful but failed when
* prepareAndUploadPoints.
*/
@UsesMocks(Cursor.class)
public void testUploadAllTrackPoints_prepareAndUploadPointsFailed() {
Track track = TrackStubUtils.createTrack(1);
Cursor cursorMock = AndroidMock.createMock(Cursor.class);
AndroidMock.expect(cursorMock.getCount()).andReturn(2);
AndroidMock.expect(cursorMock.moveToPosition(0)).andReturn(true);
AndroidMock.expect(cursorMock.moveToPosition(1)).andReturn(true);
cursorMock.close();
AndroidMock.expect(myTracksProviderUtilsMock.createTrackPoint(cursorMock))
.andReturn(new Location("1")).times(2);
AndroidMock.expect(myTracksProviderUtilsMock.getTrackPointCursor(TRACK_ID, -1L, -1, false))
.andReturn(cursorMock);
AndroidMock.replay(sendMapsActivityMock, myTracksProviderUtilsMock, cursorMock);
SendMapsAsyncTaskMock sendMapsAsyncTask = new SendMapsAsyncTaskMock(sendMapsActivityMock,
sendRequest.getTrackId(), sendRequest.getAccount(), myTracksProviderUtilsMock);
// For will be failed when run prepareAndUploadPoints, it no require to
// set uploadMarkerResult[1].
sendMapsAsyncTask.uploadMarkerResult[0] = true;
sendMapsAsyncTask.prepareAndUploadPointsResult = false;
assertFalse(sendMapsAsyncTask.uploadAllTrackPoints(track));
assertEquals(1, uploadMarkerCounter);
assertEquals(1, prepareAndUploadPointsCounter);
AndroidMock.verify(sendMapsActivityMock, myTracksProviderUtilsMock, cursorMock);
}
/**
* Tests the method {@link SendMapsAsyncTask#uploadAllTrackPoints(Track)} when
* uploads the last marker is failed.
*/
@UsesMocks(Cursor.class)
public void testUploadAllTrackPoints_uploadLastMarkerFailed() {
Track track = TrackStubUtils.createTrack(1);
Cursor cursorMock = AndroidMock.createMock(Cursor.class);
AndroidMock.expect(cursorMock.getCount()).andReturn(2);
AndroidMock.expect(cursorMock.moveToPosition(0)).andReturn(true);
AndroidMock.expect(cursorMock.moveToPosition(1)).andReturn(true);
cursorMock.close();
AndroidMock.expect(myTracksProviderUtilsMock.createTrackPoint(cursorMock))
.andReturn(new Location("1")).times(2);
AndroidMock.expect(myTracksProviderUtilsMock.getTrackPointCursor(TRACK_ID, -1L, -1, false))
.andReturn(cursorMock);
AndroidMock.replay(sendMapsActivityMock, myTracksProviderUtilsMock, cursorMock);
SendMapsAsyncTaskMock sendMapsAsyncTask = new SendMapsAsyncTaskMock(sendMapsActivityMock,
sendRequest.getTrackId(), sendRequest.getAccount(), myTracksProviderUtilsMock);
sendMapsAsyncTask.uploadMarkerResult[0] = true;
sendMapsAsyncTask.uploadMarkerResult[1] = false;
sendMapsAsyncTask.prepareAndUploadPointsResult = true;
assertFalse(sendMapsAsyncTask.uploadAllTrackPoints(track));
assertEquals(2, uploadMarkerCounter);
assertEquals(1, prepareAndUploadPointsCounter);
AndroidMock.verify(sendMapsActivityMock, myTracksProviderUtilsMock, cursorMock);
}
/**
* Tests the method {@link SendMapsAsyncTask#uploadAllTrackPoints(Track)} when
* return true.
*/
@UsesMocks(Cursor.class)
public void testUploadAllTrackPoints_success() {
Track track = TrackStubUtils.createTrack(1);
Cursor cursorMock = AndroidMock.createMock(Cursor.class);
AndroidMock.expect(cursorMock.getCount()).andReturn(2);
AndroidMock.expect(cursorMock.moveToPosition(0)).andReturn(true);
AndroidMock.expect(cursorMock.moveToPosition(1)).andReturn(true);
cursorMock.close();
AndroidMock.expect(myTracksProviderUtilsMock.createTrackPoint(cursorMock))
.andReturn(new Location("1")).times(2);
AndroidMock.expect(myTracksProviderUtilsMock.getTrackPointCursor(TRACK_ID, -1L, -1, false))
.andReturn(cursorMock);
AndroidMock.replay(sendMapsActivityMock, myTracksProviderUtilsMock, cursorMock);
SendMapsAsyncTaskMock sendMapsAsyncTask = new SendMapsAsyncTaskMock(sendMapsActivityMock,
sendRequest.getTrackId(), sendRequest.getAccount(), myTracksProviderUtilsMock);
sendMapsAsyncTask.uploadMarkerResult[0] = true;
sendMapsAsyncTask.uploadMarkerResult[1] = true;
sendMapsAsyncTask.prepareAndUploadPointsResult = true;
assertTrue(sendMapsAsyncTask.uploadAllTrackPoints(track));
assertEquals(2, uploadMarkerCounter);
assertEquals(1, prepareAndUploadPointsCounter);
AndroidMock.verify(sendMapsActivityMock, myTracksProviderUtilsMock, cursorMock);
}
/**
* Tests the method {@link SendMapsAsyncTask#uploadWaypoints()} when cursor is
* null.
*/
@UsesMocks(Cursor.class)
public void testUploadWaypoints_nullCursor() {
AndroidMock.expect(
myTracksProviderUtilsMock.getWaypointCursor(TRACK_ID, -1L,
Constants.MAX_LOADED_WAYPOINTS_POINTS)).andReturn(null);
AndroidMock.replay(sendMapsActivityMock, myTracksProviderUtilsMock);
SendMapsAsyncTask sendMapsAsyncTask = new SendMapsAsyncTask(sendMapsActivityMock,
sendRequest.getTrackId(), sendRequest.getAccount(), myTracksProviderUtilsMock);
assertTrue(sendMapsAsyncTask.uploadWaypoints());
AndroidMock.verify(sendMapsActivityMock, myTracksProviderUtilsMock);
}
/**
* Tests the method {@link SendMapsAsyncTask#uploadWaypoints()} when there is
* only one point.
*/
@UsesMocks(Cursor.class)
public void testUploadWaypoints_onePoint() {
Cursor cursorMock = AndroidMock.createMock(Cursor.class);
AndroidMock.expect(cursorMock.moveToFirst()).andReturn(true);
// Only one point, so next is null.
AndroidMock.expect(cursorMock.moveToNext()).andReturn(false);
cursorMock.close();
AndroidMock.expect(
myTracksProviderUtilsMock.getWaypointCursor(TRACK_ID, -1L,
Constants.MAX_LOADED_WAYPOINTS_POINTS)).andReturn(cursorMock);
AndroidMock.replay(sendMapsActivityMock, myTracksProviderUtilsMock, cursorMock);
SendMapsAsyncTask sendMapsAsyncTask = new SendMapsAsyncTask(sendMapsActivityMock,
sendRequest.getTrackId(), sendRequest.getAccount(), myTracksProviderUtilsMock);
assertTrue(sendMapsAsyncTask.uploadWaypoints());
AndroidMock.verify(sendMapsActivityMock, myTracksProviderUtilsMock, cursorMock);
}
/**
* Tests the method {@link SendMapsAsyncTask#uploadWaypoints()}. Makes sure a cursor is created and
* a way point is created with such cursor.
*
* @throws XmlPullParserException
*/
@UsesMocks(Cursor.class)
public void testUploadWaypoints() throws XmlPullParserException {
Cursor cursorMock = AndroidMock.createMock(Cursor.class);
MapsGDataConverter mapsGDataConverterMock = new MapsGDataConverter();
AndroidMock.expect(cursorMock.moveToFirst()).andReturn(true);
AndroidMock.expect(cursorMock.moveToNext()).andReturn(true);
cursorMock.close();
AndroidMock.expect(
myTracksProviderUtilsMock.getWaypointCursor(TRACK_ID, -1L,
Constants.MAX_LOADED_WAYPOINTS_POINTS)).andReturn(cursorMock);
Waypoint waypoint = new Waypoint();
waypoint.setLocation(TrackStubUtils.createMyTracksLocation());
AndroidMock.expect(myTracksProviderUtilsMock.createWaypoint(cursorMock)).andReturn(waypoint)
.times(1);
AndroidMock.replay(sendMapsActivityMock, myTracksProviderUtilsMock, cursorMock);
SendMapsAsyncTask sendMapsAsyncTask = new SendMapsAsyncTask(sendMapsActivityMock,
sendRequest.getTrackId(), sendRequest.getAccount(), myTracksProviderUtilsMock);
sendMapsAsyncTask.setMapsGDataConverter(mapsGDataConverterMock);
// Would be failed for there is no source for uploading.
assertFalse(sendMapsAsyncTask.uploadWaypoints());
AndroidMock.verify(sendMapsActivityMock, myTracksProviderUtilsMock, cursorMock);
}
/**
* Tests the method {@link SendMapsAsyncTask#getPercentage(int, int)}.
*/
public void testCountPercentage() {
assertEquals(SendMapsAsyncTask.PROGRESS_UPLOAD_DATA_MIN, SendMapsAsyncTask.getPercentage(0, 5));
assertEquals(SendMapsAsyncTask.PROGRESS_UPLOAD_DATA_MAX,
SendMapsAsyncTask.getPercentage(50, 50));
assertEquals(
(int) ((double) 5
/ 11
* (SendMapsAsyncTask.PROGRESS_UPLOAD_DATA_MAX - SendMapsAsyncTask.PROGRESS_UPLOAD_DATA_MIN) + SendMapsAsyncTask.PROGRESS_UPLOAD_DATA_MIN),
SendMapsAsyncTask.getPercentage(5, 11));
}
}
@@ -0,0 +1,175 @@
/*
* 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 com.google.android.apps.mytracks.io.maps;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.io.gdata.maps.MapsFeature;
import android.location.Location;
import java.util.ArrayList;
import junit.framework.TestCase;
/**
* Tests {@link SendMapsUtils}.
*
* @author Jimmy Shih
*/
public class SendMapsUtilsTest extends TestCase {
/**
* Tests {@link SendMapsUtils#getMapUrl(Track)} with null track.
*/
public void testGetMapUrl_null_track() {
assertEquals(null, SendMapsUtils.getMapUrl(null));
}
/**
* Tests {@link SendMapsUtils#getMapUrl(Track)} with null map id.
*/
public void testGetMapUrl_null_map_id() {
Track track = new Track();
track.setMapId(null);
assertEquals(null, SendMapsUtils.getMapUrl(track));
}
/**
* Tests {@link SendMapsUtils#getMapUrl(Track)} with a valid track.
*/
public void testGetMapUrl_valid_track() {
Track track = new Track();
track.setMapId("123");
assertEquals("https://maps.google.com/maps/ms?msa=0&msid=123", SendMapsUtils.getMapUrl(track));
}
/**
* Test {@link SendMapsUtils#buildMapsMarkerFeature(String, String, String,
* Location)} with a title.
*/
public void testBuildMapsMarkerFeature_with_title() {
Location location = new Location("test");
location.setLatitude(123.0);
location.setLongitude(456.0);
MapsFeature mapFeature = SendMapsUtils.buildMapsMarkerFeature(
"name", "this\nmap\ndescription", "url", location);
assertEquals(MapsFeature.MARKER, mapFeature.getType());
assertNotNull(mapFeature.getAndroidId());
assertEquals("name", mapFeature.getTitle());
assertEquals("this<br>map<br>description", mapFeature.getDescription());
assertEquals("url", mapFeature.getIconUrl());
assertEquals(123.0, mapFeature.getPoint(0).getLatitude());
assertEquals(456.0, mapFeature.getPoint(0).getLongitude());
}
/**
* Test {@link SendMapsUtils#buildMapsMarkerFeature(String, String, String,
* Location)} with an empty title.
*/
public void testBuildMapsMarkerFeature_empty_title() {
Location location = new Location("test");
location.setLatitude(123.0);
location.setLongitude(456.0);
MapsFeature mapFeature = SendMapsUtils.buildMapsMarkerFeature(
"", "description", "url", location);
assertEquals(MapsFeature.MARKER, mapFeature.getType());
assertNotNull(mapFeature.getAndroidId());
assertEquals("-", mapFeature.getTitle());
assertEquals("description", mapFeature.getDescription());
assertEquals("url", mapFeature.getIconUrl());
assertEquals(123.0, mapFeature.getPoint(0).getLatitude());
assertEquals(456.0, mapFeature.getPoint(0).getLongitude());
}
/**
* Test {@link SendMapsUtils#buildMapsMarkerFeature(String, String, String,
* Location)} with a null title.
*/
public void testBuildMapsMarkerFeature_null_title() {
Location location = new Location("test");
location.setLatitude(123.0);
location.setLongitude(456.0);
MapsFeature mapFeature = SendMapsUtils.buildMapsMarkerFeature(
null, "description", "url", location);
assertEquals(MapsFeature.MARKER, mapFeature.getType());
assertNotNull(mapFeature.getAndroidId());
assertEquals("-", mapFeature.getTitle());
assertEquals("description", mapFeature.getDescription());
assertEquals("url", mapFeature.getIconUrl());
assertEquals(123.0, mapFeature.getPoint(0).getLatitude());
assertEquals(456.0, mapFeature.getPoint(0).getLongitude());
}
/**
* Test {@link SendMapsUtils#buildMapsLineFeature(String, ArrayList)} with a
* title.
*/
public void testBuildMapsLineFeature_with_title() {
ArrayList<Location> locations = new ArrayList<Location>();
Location location = new Location("test");
location.setLatitude(50.0);
location.setLongitude(100.0);
locations.add(location);
MapsFeature mapFeature = SendMapsUtils.buildMapsLineFeature("name", locations);
assertEquals(MapsFeature.LINE, mapFeature.getType());
assertNotNull(mapFeature.getAndroidId());
assertEquals("name", mapFeature.getTitle());
assertEquals(0x80FF0000, mapFeature.getColor());
assertEquals(50.0, mapFeature.getPoint(0).getLatitude());
assertEquals(100.0, mapFeature.getPoint(0).getLongitude());
}
/**
* Test {@link SendMapsUtils#buildMapsLineFeature(String, ArrayList)} with an
* empty title.
*/
public void testBuildMapsLineFeature_empty_title() {
ArrayList<Location> locations = new ArrayList<Location>();
Location location = new Location("test");
location.setLatitude(50.0);
location.setLongitude(100.0);
locations.add(location);
MapsFeature mapFeature = SendMapsUtils.buildMapsLineFeature("", locations);
assertEquals(MapsFeature.LINE, mapFeature.getType());
assertNotNull(mapFeature.getAndroidId());
assertEquals("-", mapFeature.getTitle());
assertEquals(0x80FF0000, mapFeature.getColor());
assertEquals(50.0, mapFeature.getPoint(0).getLatitude());
assertEquals(100.0, mapFeature.getPoint(0).getLongitude());
}
/**
* Test {@link SendMapsUtils#buildMapsLineFeature(String, ArrayList)} with a
* null title.
*/
public void testBuildMapsLineFeature_null_title() {
ArrayList<Location> locations = new ArrayList<Location>();
Location location = new Location("test");
location.setLatitude(50.0);
location.setLongitude(100.0);
locations.add(location);
MapsFeature mapFeature = SendMapsUtils.buildMapsLineFeature(null, locations);
assertEquals(MapsFeature.LINE, mapFeature.getType());
assertNotNull(mapFeature.getAndroidId());
assertEquals("-", mapFeature.getTitle());
assertEquals(0x80FF0000, mapFeature.getColor());
assertEquals(50.0, mapFeature.getPoint(0).getLatitude());
assertEquals(100.0, mapFeature.getPoint(0).getLongitude());
}
}
@@ -0,0 +1,277 @@
/*
* 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 com.google.android.apps.mytracks.io.sendtogoogle;
import android.accounts.Account;
import android.os.Parcel;
import android.os.Parcelable;
import android.test.AndroidTestCase;
/**
* Tests the {@link SendRequest}.
*
* @author Youtao Liu
*/
public class SendRequestTest extends AndroidTestCase {
private SendRequest sendRequest;
private final static String ACCOUNTNAME = "testAccount1";
private final static String ACCOUNTYPE = "testType1";
private final static String DRIVE_SHARE_EMAILS = "foo@foo.com";
@Override
protected void setUp() throws Exception {
super.setUp();
sendRequest = new SendRequest(1);
}
/**
* Tests the method {@link SendRequest#getTrackId()}. The value should be set
* to 1 when it is initialed in setup method.
*/
public void testGetTrackId() {
assertEquals(1, sendRequest.getTrackId());
}
public void testIsSendMaps() {
assertEquals(false, sendRequest.isSendMaps());
sendRequest.setSendMaps(true);
assertEquals(true, sendRequest.isSendMaps());
}
public void testIsSendFusionTables() {
assertEquals(false, sendRequest.isSendFusionTables());
sendRequest.setSendFusionTables(true);
assertEquals(true, sendRequest.isSendFusionTables());
}
/**
* Tests the method {@link SendRequest#isSendSpreadsheets()}. The value should
* be set to false which is its default value when it is initialed in setup
* method.
*/
public void testIsSendSpreadsheets() {
assertEquals(false, sendRequest.isSendSpreadsheets());
sendRequest.setSendSpreadsheets(true);
assertEquals(true, sendRequest.isSendSpreadsheets());
}
/**
* Tests the method {@link SendRequest#getAccount()}. The value should be set
* to null which is its default value when it is initialed in setup method.
*/
public void testGetAccount() {
assertEquals(null, sendRequest.getAccount());
Account account = new Account(ACCOUNTNAME, ACCOUNTYPE);
sendRequest.setAccount(account);
assertEquals(account, sendRequest.getAccount());
}
/**
* Tests the method {@link SendRequest#isMapsSuccess()}. The value should be
* set to false which is its default value when it is initialed in setup
* method.
*/
public void testIsMapsSuccess() {
assertEquals(false, sendRequest.isMapsSuccess());
sendRequest.setMapsSuccess(true);
assertEquals(true, sendRequest.isMapsSuccess());
}
/**
* Tests the method {@link SendRequest#isFusionTablesSuccess()}. The value
* should be set to false which is its default value when it is initialed in
* setup method.
*/
public void testIsFusionTablesSuccess() {
assertEquals(false, sendRequest.isFusionTablesSuccess());
sendRequest.setFusionTablesSuccess(true);
assertEquals(true, sendRequest.isFusionTablesSuccess());
}
/**
* Tests the method {@link SendRequest#isSpreadsheetsSuccess()}. The value
* should be set to false which is its default value when it is initialed in
* setup method.
*/
public void testIsSpreadsheetsSuccess() {
assertEquals(false, sendRequest.isSpreadsheetsSuccess());
sendRequest.setSpreadsheetsSuccess(true);
assertEquals(true, sendRequest.isSpreadsheetsSuccess());
}
/**
* Tests SendRequest.CREATOR.createFromParcel when all values are true.
*/
public void testCreateFromParcel_true() {
Parcel parcel = Parcel.obtain();
parcel.setDataPosition(0);
parcel.writeLong(2);
parcel.writeByte((byte) 1);
parcel.writeByte((byte) 1);
parcel.writeByte((byte) 1);
parcel.writeByte((byte) 1);
parcel.writeByte((byte) 1);
parcel.writeByte((byte) 1);
parcel.writeString(DRIVE_SHARE_EMAILS);
Account account = new Account(ACCOUNTNAME, ACCOUNTYPE);
parcel.writeParcelable(account, 0);
parcel.writeByte((byte) 1);
parcel.writeByte((byte) 1);
parcel.writeByte((byte) 1);
parcel.writeByte((byte) 1);
parcel.setDataPosition(0);
sendRequest = SendRequest.CREATOR.createFromParcel(parcel);
assertEquals(2, sendRequest.getTrackId());
assertTrue(sendRequest.isSendDrive());
assertTrue(sendRequest.isSendMaps());
assertTrue(sendRequest.isSendFusionTables());
assertTrue(sendRequest.isSendSpreadsheets());
assertTrue(sendRequest.isDriveEnableSync());
assertTrue(sendRequest.isDriveShare());
assertEquals(DRIVE_SHARE_EMAILS, sendRequest.getDriveShareEmails());
assertEquals(account, sendRequest.getAccount());
assertTrue(sendRequest.isDriveSuccess());
assertTrue(sendRequest.isMapsSuccess());
assertTrue(sendRequest.isFusionTablesSuccess());
assertTrue(sendRequest.isSpreadsheetsSuccess());
}
/**
* Tests SendRequest.CREATOR.createFromParcel when all values are false.
*/
public void testCreateFromParcel_false() {
Parcel parcel = Parcel.obtain();
parcel.setDataPosition(0);
parcel.writeLong(4);
parcel.writeByte((byte) 0);
parcel.writeByte((byte) 0);
parcel.writeByte((byte) 0);
parcel.writeByte((byte) 0);
parcel.writeByte((byte) 0);
parcel.writeByte((byte) 0);
parcel.writeString(null);
Account account = new Account(ACCOUNTNAME, ACCOUNTYPE);
parcel.writeParcelable(account, 0);
parcel.writeByte((byte) 0);
parcel.writeByte((byte) 0);
parcel.writeByte((byte) 0);
parcel.writeByte((byte) 0);
parcel.setDataPosition(0);
sendRequest = SendRequest.CREATOR.createFromParcel(parcel);
assertEquals(4, sendRequest.getTrackId());
assertFalse(sendRequest.isSendDrive());
assertFalse(sendRequest.isSendMaps());
assertFalse(sendRequest.isSendFusionTables());
assertFalse(sendRequest.isSendSpreadsheets());
assertFalse(sendRequest.isDriveEnableSync());
assertFalse(sendRequest.isDriveShare());
assertNull(sendRequest.getDriveShareEmails());
assertEquals(account, sendRequest.getAccount());
assertFalse(sendRequest.isDriveSuccess());
assertFalse(sendRequest.isMapsSuccess());
assertFalse(sendRequest.isFusionTablesSuccess());
assertFalse(sendRequest.isSpreadsheetsSuccess());
}
/**
* Tests {@link SendRequest#writeToParcel(Parcel, int)} with default values.
*/
public void testWriteToParcel_default() {
sendRequest = new SendRequest(1);
Parcel parcel = Parcel.obtain();
parcel.setDataPosition(0);
sendRequest.writeToParcel(parcel, 1);
parcel.setDataPosition(0);
long trackId = parcel.readLong();
boolean sendDrive = parcel.readByte() == 1;
boolean sendMaps = parcel.readByte() == 1;
boolean sendFusionTables = parcel.readByte() == 1;
boolean sendSpreadsheets = parcel.readByte() == 1;
boolean driveEnableSync = parcel.readByte() == 1;
boolean driveShare = parcel.readByte() == 1;
String dirveShareEmails = parcel.readString();
Parcelable account = parcel.readParcelable(null);
boolean driveSuccess = parcel.readByte() == 1;
boolean mapsSuccess = parcel.readByte() == 1;
boolean fusionTablesSuccess = parcel.readByte() == 1;
boolean spreadsheetsSuccess = parcel.readByte() == 1;
assertEquals(1, trackId);
assertFalse(sendDrive);
assertFalse(sendMaps);
assertFalse(sendFusionTables);
assertFalse(sendSpreadsheets);
assertFalse(driveEnableSync);
assertFalse(driveShare);
assertNull(dirveShareEmails);
assertNull(account);
assertFalse(driveSuccess);
assertFalse(mapsSuccess);
assertFalse(fusionTablesSuccess);
assertFalse(spreadsheetsSuccess);
}
/**
* Tests {@link SendRequest#writeToParcel(Parcel, int)}.
*/
public void testWriteToParcel() {
sendRequest = new SendRequest(4);
sendRequest.setSendDrive(true);
sendRequest.setSendMaps(true);
sendRequest.setSendFusionTables(true);
sendRequest.setSendSpreadsheets(true);
sendRequest.setDriveEnableSync(true);
sendRequest.setDriveShare(true);
sendRequest.setDriveShareEmails(DRIVE_SHARE_EMAILS);
Account accountNew = new Account(ACCOUNTNAME + "2", ACCOUNTYPE + "2");
sendRequest.setAccount(accountNew);
sendRequest.setMapsSuccess(true);
sendRequest.setDriveSuccess(true);
sendRequest.setFusionTablesSuccess(true);
sendRequest.setSpreadsheetsSuccess(true);
Parcel parcel = Parcel.obtain();
parcel.setDataPosition(0);
sendRequest.writeToParcel(parcel, 1);
parcel.setDataPosition(0);
long trackId = parcel.readLong();
boolean sendDrive = parcel.readByte() == 1;
boolean sendMaps = parcel.readByte() == 1;
boolean sendFusionTables = parcel.readByte() == 1;
boolean sendSpreadsheets = parcel.readByte() == 1;
boolean driveEnableSync = parcel.readByte() == 1;
boolean driveShare = parcel.readByte() == 1;
String driveShareEmails = parcel.readString();
Parcelable account = parcel.readParcelable(null);
boolean driveSuccess = parcel.readByte() == 1;
boolean mapsSuccess = parcel.readByte() == 1;
boolean fusionTablesSuccess = parcel.readByte() == 1;
boolean spreadsheetsSuccess = parcel.readByte() == 1;
assertEquals(4, trackId);
assertTrue(sendDrive);
assertTrue(sendMaps);
assertTrue(sendFusionTables);
assertTrue(sendSpreadsheets);
assertTrue(driveEnableSync);
assertTrue(driveShare);
assertEquals(DRIVE_SHARE_EMAILS, driveShareEmails);
assertEquals(accountNew, account);
assertTrue(driveSuccess);
assertTrue(mapsSuccess);
assertTrue(fusionTablesSuccess);
assertTrue(spreadsheetsSuccess);
}
}
@@ -0,0 +1,124 @@
/*
* 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 com.google.android.apps.mytracks.io.sendtogoogle;
/**
* Tests the {@link SendToGoogleUtils}.
*
* @author Youtao Liu
*/
import com.google.android.apps.mytracks.TrackStubUtils;
import com.google.android.apps.mytracks.content.MyTracksLocation;
import com.google.android.apps.mytracks.content.Track;
import android.location.Location;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
public class SendToGoogleUtilsTest extends TestCase {
private final static long TRACK_ID = 1L;
private final static String TRACK_CATEGORY = "trackCategory";
private final static String TRACK_NAME = "trackName";
private final static double DIFFERENCE = 0.02;
private final static double INVALID_LATITUDE = 91;
/**
* Tests the method
* {@link SendToGoogleUtils#endSegment(Track, long, ArrayList)}
* when there is only one location in a segment.
*/
public void testPrepareTrackSegment_onlyOneLocation() {
Track segment = TrackStubUtils.createTrack(1);
assertFalse(SendToGoogleUtils.endSegment(segment, -1L, null));
}
/**
* Tests the method
* {@link SendToGoogleUtils#endSegment(Track, long, ArrayList)} when there
* is no stop time.
*/
public void testPrepareTrackSegment_noStopTime() {
Track segment = TrackStubUtils.createTrack(2);
assertEquals(-1L, segment.getTripStatistics().getStopTime());
ArrayList<Track> tracksArray = new ArrayList<Track>();
assertTrue(SendToGoogleUtils.endSegment(
segment, segment.getLocations().get(1).getTime(), tracksArray));
assertEquals(segment, tracksArray.get(0));
// The stop time should be the time of last location
assertEquals(
segment.getLocations().get(1).getTime(), segment.getTripStatistics().getStopTime());
}
/**
* Tests the method
* {@link SendToGoogleUtils#prepareLocations(Track, java.util.List)} .
*/
public void testPrepareLocations() {
Track trackStub = TrackStubUtils.createTrack(2);
trackStub.setId(TRACK_ID);
trackStub.setName(TRACK_NAME);
trackStub.setCategory(TRACK_CATEGORY);
List<Location> locationsArray = new ArrayList<Location>();
// Adds 100 location to List.
for (int i = 0; i < 100; i++) {
// Use this variable as a flag to make all points in the track can be kept
// after run the LocationUtils#decimate(Track, double) with
// Ramer–Douglas–Peucker algorithm.
double latitude = TrackStubUtils.INITIAL_LATITUDE;
if (i % 2 == 0) {
latitude -= DIFFERENCE * (i % 10);
}
// Inserts 9 points which have wrong latitude, so would have 10 segments.
if (i % 10 == 0 && i > 0) {
MyTracksLocation location = TrackStubUtils.createMyTracksLocation();
location.setLatitude(INVALID_LATITUDE);
locationsArray.add(location);
} else {
locationsArray.add(TrackStubUtils.createMyTracksLocation(latitude,
TrackStubUtils.INITIAL_LONGITUDE + DIFFERENCE * (i % 10),
TrackStubUtils.INITIAL_ALTITUDE + DIFFERENCE * (i % 10)));
}
}
ArrayList<Track> result = SendToGoogleUtils.prepareLocations(trackStub, locationsArray);
assertEquals(10, result.size());
// Checks all segments.
for (int i = 0; i < 10; i++) {
Track segmentOne = result.get(i);
assertEquals(TRACK_ID, segmentOne.getId());
assertEquals(TRACK_NAME, segmentOne.getName());
assertEquals(TRACK_CATEGORY, segmentOne.getCategory());
}
// Checks all locations in the first segment.
for (int j = 0; j < 9; j++) {
double latitude = TrackStubUtils.INITIAL_LATITUDE;
if (j % 2 == 0) {
latitude -= DIFFERENCE * (j % 10);
}
Location oneLocation = result.get(0).getLocations().get(j);
assertEquals(TrackStubUtils.createMyTracksLocation().getAltitude() + DIFFERENCE * (j % 10),
oneLocation.getAltitude());
assertEquals(latitude, oneLocation.getLatitude());
assertEquals(TrackStubUtils.createMyTracksLocation().getLongitude() + DIFFERENCE * (j % 10),
oneLocation.getLongitude());
}
}
}
@@ -0,0 +1,159 @@
/*
* 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 com.google.android.apps.mytracks.io.sendtogoogle;
import com.google.android.maps.mytracks.R;
import android.content.Intent;
import android.test.ActivityInstrumentationTestCase2;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
/**
* Tests the {@link UploadResultActivity}.
*
* @author Youtao Liu
*/
public class UploadResultActivityTest extends
ActivityInstrumentationTestCase2<UploadResultActivity> {
private UploadResultActivity uploadResultActivity;
private TextView errorFooter;
private TextView successFooter;
private LinearLayout mapsResult;
private LinearLayout fusionTablesResult;
private LinearLayout spreadsheetsResult;
private ImageView mapsResultIcon;
private ImageView fusionTablesResultIcon;
private ImageView spreadsheetsResultIcon;
private String successTitle;
private String errorTitle;
/**
* This method is necessary for ActivityInstrumentationTestCase2.
*/
public UploadResultActivityTest() {
super(UploadResultActivity.class);
}
/**
* Checks the display of dialog when send to all and all sends are successful.
*/
public void testAllSuccess() {
initialActivity(true, true, true, true, true, true);
createDialogAndGetViews();
assertEquals(View.VISIBLE, successFooter.getVisibility());
assertEquals(View.GONE, errorFooter.getVisibility());
assertEquals(View.VISIBLE, mapsResult.getVisibility());
assertEquals(View.VISIBLE, fusionTablesResult.getVisibility());
assertEquals(View.VISIBLE, spreadsheetsResult.getVisibility());
assertEquals(successTitle, mapsResultIcon.getContentDescription());
assertEquals(successTitle, fusionTablesResultIcon.getContentDescription());
assertEquals(successTitle, spreadsheetsResultIcon.getContentDescription());
}
/**
* Checks the display of dialog when send to all and all sends are failed.
*/
public void testAllFailed() {
// Send all kinds but all failed.
initialActivity(true, true, true, false, false, false);
createDialogAndGetViews();
assertEquals(View.GONE, successFooter.getVisibility());
assertEquals(View.VISIBLE, errorFooter.getVisibility());
assertEquals(View.VISIBLE, mapsResult.getVisibility());
assertEquals(View.VISIBLE, fusionTablesResult.getVisibility());
assertEquals(View.VISIBLE, spreadsheetsResult.getVisibility());
assertEquals(errorTitle, mapsResultIcon.getContentDescription());
assertEquals(errorTitle, fusionTablesResultIcon.getContentDescription());
assertEquals(errorTitle, spreadsheetsResultIcon.getContentDescription());
}
/**
* Checks the display of dialog when match following items:
* <ul>
* <li>Only send to Maps and Spreadsheets.</li>
* <li>Send to Maps successful.</li>
* <li>Send to Spreadsheets failed.</li>
* </ul>
*/
public void testPartialSuccess() {
initialActivity(true, false, true, true, false, false);
createDialogAndGetViews();
assertEquals(View.VISIBLE, errorFooter.getVisibility());
assertEquals(View.VISIBLE, mapsResult.getVisibility());
assertEquals(View.GONE, fusionTablesResult.getVisibility());
assertEquals(View.VISIBLE, spreadsheetsResult.getVisibility());
assertEquals(successTitle, mapsResultIcon.getContentDescription());
assertEquals(errorTitle, spreadsheetsResultIcon.getContentDescription());
}
/**
* Initials a {@link SendRequest} and then initials a activity to be tested.
*
* @param isSendMaps
* @param isSendFusionTables
* @param isSendSpreadsheets
* @param isMapsSuccess
* @param isFusionTablesSuccess
* @param isSpreadsheetSuccess
*/
private void initialActivity(boolean isSendMaps, boolean isSendFusionTables, boolean isSendSpreadsheets,
boolean isMapsSuccess, boolean isFusionTablesSuccess, boolean isSpreadsheetSuccess) {
Intent intent = new Intent();
SendRequest sendRequest = new SendRequest(1L);
sendRequest.setSendMaps(isSendMaps);
sendRequest.setSendFusionTables(isSendFusionTables);
sendRequest.setSendSpreadsheets(isSendSpreadsheets);
sendRequest.setMapsSuccess(isMapsSuccess);
sendRequest.setFusionTablesSuccess(isFusionTablesSuccess);
sendRequest.setSpreadsheetsSuccess(isSpreadsheetSuccess);
intent.putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest);
setActivityIntent(intent);
uploadResultActivity = this.getActivity();
successTitle = uploadResultActivity.getString(R.string.generic_success_title);
errorTitle = uploadResultActivity.getString(R.string.generic_error_title);
}
/**
* Creates result dialog and gets views in the dialog.
*/
private void createDialogAndGetViews() {
uploadResultActivity.onCreateDialog(UploadResultActivity.DIALOG_RESULT_ID);
View view = uploadResultActivity.view;
errorFooter = (TextView) view.findViewById(R.id.upload_result_error_footer);
successFooter = (TextView) view.findViewById(R.id.upload_result_success_footer);
mapsResult = (LinearLayout) view.findViewById(R.id.upload_result_maps_result);
fusionTablesResult = (LinearLayout) view.findViewById(R.id.upload_result_fusion_tables_result);
spreadsheetsResult = (LinearLayout) view.findViewById(R.id.upload_result_spreadsheets_result);
mapsResultIcon = (ImageView) view.findViewById(R.id.upload_result_maps_result_icon);
fusionTablesResultIcon = (ImageView) view
.findViewById(R.id.upload_result_fusion_tables_result_icon);
spreadsheetsResultIcon = (ImageView) view.findViewById(R.id.upload_result_spreadsheets_result_icon);
}
}
@@ -0,0 +1,74 @@
/*
* 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 com.google.android.apps.mytracks.io.spreadsheets;
import com.google.android.apps.mytracks.io.spreadsheets.SendSpreadsheetsUtils;
import android.test.AndroidTestCase;
/**
* Tests {@link SendSpreadsheetsUtils}.
*
* @author Jimmy Shih
*/
public class SendSpreadsheetsUtilsTest extends AndroidTestCase {
/**
* Tests {@link SendSpreadsheetsUtils#getDistance(double, boolean)} with metric units.
*/
public void testGetDistance_metric() {
assertEquals("1.22", SendSpreadsheetsUtils.getDistance(1222.3, true));
}
/**
* Tests {@link SendSpreadsheetsUtils#getDistance(double, boolean)} with imperial
* units.
*/
public void testGetDistance_imperial() {
assertEquals("0.76", SendSpreadsheetsUtils.getDistance(1222.3, false));
}
/**
* Tests {@link SendSpreadsheetsUtils#getSpeed(double, boolean)} with metric units.
*/
public void testGetSpeed_metric() {
assertEquals("15.55", SendSpreadsheetsUtils.getSpeed(4.32, true));
}
/**
* Tests {@link SendSpreadsheetsUtils#getSpeed(double, boolean)} with imperial units.
*/
public void testGetSpeed_imperial() {
assertEquals("9.66", SendSpreadsheetsUtils.getSpeed(4.32, false));
}
/**
* Tests {@link SendSpreadsheetsUtils#getElevation(double, boolean)} with metric
* units.
*/
public void testGetElevation_metric() {
assertEquals("3", SendSpreadsheetsUtils.getElevation(3.456, true));
}
/**
* Tests {@link SendSpreadsheetsUtils#getElevation(double, boolean)} with imperial
* units.
*/
public void testGetElevation_imperial() {
assertEquals("11", SendSpreadsheetsUtils.getElevation(3.456, false));
}
}
@@ -0,0 +1,104 @@
/*
* 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 com.google.android.apps.mytracks.maps;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
import android.content.Context;
import android.test.AndroidTestCase;
/**
* Tests for the {@link DynamicSpeedTrackPathDescriptor}.
*
* @author Youtao Liu
*/
public class DynamicSpeedTrackPathDescriptorTest extends AndroidTestCase {
private Context context;
@Override
protected void setUp() throws Exception {
super.setUp();
context = getContext();
}
/**
* Tests the method {@link DynamicSpeedTrackPathDescriptor#getSpeedMargin()}
* with zero, normal and illegal value.
*/
public void testGetSpeedMargin() {
// The default value of speedMargin is 25.
int[] expectations = { 0, 50, 99, 25 };
// Test
for (int i = 0; i < expectations.length; i++) {
PreferencesUtils.setInt(context, R.string.track_color_mode_percentage_key, expectations[i]);
DynamicSpeedTrackPathDescriptor dynamicSpeedTrackPathDescriptor = new DynamicSpeedTrackPathDescriptor(
context);
assertEquals(expectations[i], dynamicSpeedTrackPathDescriptor.getSpeedMargin());
}
}
/**
* Tests {@link DynamicSpeedTrackPathDescriptor#getSlowSpeed()}.
*/
public void testGetSlowSpeed() {
DynamicSpeedTrackPathDescriptor dynamicSpeedTrackPathDescriptor = new DynamicSpeedTrackPathDescriptor(
context);
dynamicSpeedTrackPathDescriptor.setAverageMovingSpeed(50);
dynamicSpeedTrackPathDescriptor.setSpeedMargin(10);
assertEquals(50.0, dynamicSpeedTrackPathDescriptor.getAverageMovingSpeed());
assertEquals(45, dynamicSpeedTrackPathDescriptor.getSlowSpeed());
}
/**
* Tests {@link DynamicSpeedTrackPathDescriptor#getNormalSpeed()}.
*/
public void testGetNormalSpeed() {
DynamicSpeedTrackPathDescriptor dynamicSpeedTrackPathDescriptor = new DynamicSpeedTrackPathDescriptor(
context);
dynamicSpeedTrackPathDescriptor.setAverageMovingSpeed(50);
dynamicSpeedTrackPathDescriptor.setSpeedMargin(10);
assertEquals(50.0, dynamicSpeedTrackPathDescriptor.getAverageMovingSpeed());
assertEquals(55, dynamicSpeedTrackPathDescriptor.getNormalSpeed());
}
/**
* Tests {@link DynamicSpeedTrackPathDescriptor#updateState(com.google.android.apps.mytracks.stats.TripStatistics)}
* by different averageMovingSpeed.
*/
public void testIsDiffereceSignificant() {
DynamicSpeedTrackPathDescriptor dynamicSpeedTrackPathDescriptor = new DynamicSpeedTrackPathDescriptor(
context);
double[] averageMovingSpeeds = { 0, 30, 30, 30 };
double[] newAverageMovingSpeed = { 20, 30,
// Difference is less than CRITICAL_DIFFERENCE_PERCENTAGE
30 * (1 + (DynamicSpeedTrackPathDescriptor.CRITICAL_DIFFERENCE_PERCENTAGE / 100) / 2),
// Difference is more than CRITICAL_DIFFERENCE_PERCENTAGE
30 * (1 + (DynamicSpeedTrackPathDescriptor.CRITICAL_DIFFERENCE_PERCENTAGE / 100.00) * 2) };
boolean[] expectedValues = { true, false, false, true };
double[] expectedAverageMovingSpeed = { 0, 30, 30, 30 };
// Test
for (int i = 0; i < newAverageMovingSpeed.length; i++) {
dynamicSpeedTrackPathDescriptor.setAverageMovingSpeed(averageMovingSpeeds[i]);
assertEquals(expectedValues[i], dynamicSpeedTrackPathDescriptor.isDifferenceSignificant(
averageMovingSpeeds[i], newAverageMovingSpeed[i]));
assertEquals(expectedAverageMovingSpeed[i],
dynamicSpeedTrackPathDescriptor.getAverageMovingSpeed());
}
}
}
@@ -0,0 +1,73 @@
/*
* 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 com.google.android.apps.mytracks.maps;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
import android.content.Context;
import android.test.AndroidTestCase;
/**
* Tests for the {@link DynamicSpeedTrackPathDescriptor}.
*
* @author Youtao Liu
*/
public class FixedSpeedTrackPathDescriptorTest extends AndroidTestCase {
private Context context;
@Override
protected void setUp() throws Exception {
super.setUp();
context = getContext();
}
/**
* Tests the initialization of slowSpeed and normalSpeed in {@link DynamicSpeedTrackPathDescriptor#DynamicSpeedTrackPathDescriptor(Context)}
* .
*/
public void testConstructor() {
int[] slowSpeedExpectations = { 0, 1, 99, PreferencesUtils.TRACK_COLOR_MODE_SLOW_DEFAULT };
int[] normalSpeedExpectations = { 0, 1, 99, PreferencesUtils.TRACK_COLOR_MODE_MEDIUM_DEFAULT };
for (int i = 0; i < slowSpeedExpectations.length; i++) {
PreferencesUtils.setInt(
context, R.string.track_color_mode_slow_key, slowSpeedExpectations[i]);
PreferencesUtils.setInt(
context, R.string.track_color_mode_medium_key, normalSpeedExpectations[i]);
FixedSpeedTrackPathDescriptor fixedSpeedTrackPathDescriptor = new FixedSpeedTrackPathDescriptor(
context);
assertEquals(slowSpeedExpectations[i], fixedSpeedTrackPathDescriptor.getSlowSpeed());
assertEquals(normalSpeedExpectations[i], fixedSpeedTrackPathDescriptor.getNormalSpeed());
}
}
/**
* Tests {@link FixedSpeedTrackPathDescriptor#getSlowSpeed()} and
* {@link FixedSpeedTrackPathDescriptor#getNormalSpeed()}.
*/
public void testGetSpeed() {
FixedSpeedTrackPathDescriptor fixedSpeedTrackPathDescriptor = new FixedSpeedTrackPathDescriptor(
context);
int slowSpeed = fixedSpeedTrackPathDescriptor.getSlowSpeed();
int normalSpeed = fixedSpeedTrackPathDescriptor.getNormalSpeed();
// Change value in shared preferences
PreferencesUtils.setInt(context, R.string.track_color_mode_slow_key, slowSpeed + 2);
PreferencesUtils.setInt(context, R.string.track_color_mode_medium_key, normalSpeed + 2);
assertEquals(slowSpeed, fixedSpeedTrackPathDescriptor.getSlowSpeed());
assertEquals(normalSpeed, fixedSpeedTrackPathDescriptor.getNormalSpeed());
}
}
@@ -0,0 +1,60 @@
/*
* 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 com.google.android.apps.mytracks.maps;
import android.content.Context;
import android.test.AndroidTestCase;
/**
* Tests for the {@link MultiColorTrackPath}.
*
* @author Youtao Liu
*/
public class MultiColorTrackPathTest extends AndroidTestCase {
private MultiColorTrackPath multiColorTrackPath;
private Context context;
@Override
protected void setUp() throws Exception {
super.setUp();
context = getContext();
}
/**
* Tests the {@link MultiColorTrackPath#getColor(int)} when use dynamic speed
* track path descriptor.
*/
public void testGetColor_DynamicSpeedTrackPathDescriptor() {
DynamicSpeedTrackPathDescriptor dynamicSpeedTrackPathDescriptor = new DynamicSpeedTrackPathDescriptor(
context);
dynamicSpeedTrackPathDescriptor.setAverageMovingSpeed(50);
dynamicSpeedTrackPathDescriptor.setSpeedMargin(10);
multiColorTrackPath = new MultiColorTrackPath(context, dynamicSpeedTrackPathDescriptor);
// Slow speed should be below 45 (10% of 50), and fast speed should be above
// 55 (10% of 50).
assertEquals(multiColorTrackPath.getSlowColor(), multiColorTrackPath.getColor(5));
assertEquals(multiColorTrackPath.getSlowColor(), multiColorTrackPath.getColor(44));
assertEquals(multiColorTrackPath.getNormalColor(), multiColorTrackPath.getColor(50));
assertEquals(multiColorTrackPath.getNormalColor(), multiColorTrackPath.getColor(54));
assertEquals(multiColorTrackPath.getFastColor(), multiColorTrackPath.getColor(56));
assertEquals(multiColorTrackPath.getFastColor(), multiColorTrackPath.getColor(100));
assertNotSame(multiColorTrackPath.getSlowColor(), multiColorTrackPath.getNormalColor());
assertNotSame(multiColorTrackPath.getSlowColor(), multiColorTrackPath.getFastColor());
}
}
@@ -0,0 +1,76 @@
/*
* 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 com.google.android.apps.mytracks.services;
import junit.framework.TestCase;
/**
* Tests the {@link AdaptiveLocationListenerPolicy}.
*
* @author youtaol
*/
public class AdaptiveLocationListenerPolicyTest extends TestCase {
private AdaptiveLocationListenerPolicy adocationListenerPolicy;
private static final long MIN = 1000;
private static final long MAX = 3000;
private static final int MIN_DISTANCE = 10;
private static final long NEW_IDLE_TIME_BIG = 10000;
private static final long NEW_IDLE_TIME_NORMAL = 5000;
private static final long NEW_IDLE_TIME_SMALL = 2000;
private static final long NEW_IDLE_TIME_LESS_THAN_MIN = 500;
@Override
protected void setUp() throws Exception {
super.setUp();
adocationListenerPolicy = new AdaptiveLocationListenerPolicy(MIN, MAX, MIN_DISTANCE);
}
/**
* Tests the
* {@link AdaptiveLocationListenerPolicy#getDesiredPollingInterval()} in four
* situations.
* <ul>
* <li>The newIdleTime is bigger than max interval.</li>
* <li>The newIdleTime is between min and max interval.</li>
* <li>The newIdleTime is smaller than max interval.</li>
* <li>The newIdleTime is smaller than the smallest interval unit.</li>
* </ul>
*/
public void testGetDesiredPollingInterval() {
adocationListenerPolicy.updateIdleTime(NEW_IDLE_TIME_BIG);
assertEquals(MAX, adocationListenerPolicy.getDesiredPollingInterval());
adocationListenerPolicy.updateIdleTime(NEW_IDLE_TIME_NORMAL);
// First get the half of NEW_IDLE_TIME_NORMAL, and then round it to the
// nearest second.
assertEquals((NEW_IDLE_TIME_NORMAL / 2 / 1000) * 1000,
adocationListenerPolicy.getDesiredPollingInterval());
adocationListenerPolicy.updateIdleTime(NEW_IDLE_TIME_SMALL);
assertEquals(MIN, adocationListenerPolicy.getDesiredPollingInterval());
adocationListenerPolicy.updateIdleTime(NEW_IDLE_TIME_LESS_THAN_MIN);
assertEquals(MIN, adocationListenerPolicy.getDesiredPollingInterval());
}
/**
* Tests the method {@link AdaptiveLocationListenerPolicy#getMinDistance()}.
*/
public void testGetMinDistance() {
assertEquals(MIN_DISTANCE, adocationListenerPolicy.getMinDistance());
}
}
@@ -0,0 +1,105 @@
/*
* 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 com.google.android.apps.mytracks.services;
import com.google.android.maps.mytracks.R;
import com.google.android.testing.mocking.UsesMocks;
import android.content.Context;
import android.content.Intent;
import android.os.RemoteException;
import android.test.ServiceTestCase;
import org.easymock.EasyMock;
/**
* Tests {@link ControlRecordingService}.
*
* @author Youtao Liu
*/
public class ControlRecordingServiceTest extends ServiceTestCase<ControlRecordingService> {
private Context context;
private ControlRecordingService controlRecordingService;
public ControlRecordingServiceTest() {
super(ControlRecordingService.class);
}
@Override
protected void setUp() throws Exception {
super.setUp();
context = getContext();
}
/**
* Tests the start of {@link ControlRecordingService} and tests the method
* {@link ControlRecordingService#onHandleIntent(Intent, ITrackRecordingService)}
* to start a track recording.
*/
@UsesMocks(ITrackRecordingService.class)
public void testStartRecording() {
assertNull(controlRecordingService);
Intent intent = startControlRecordingService(context.getString(R.string.track_action_start));
assertNotNull(controlRecordingService);
ITrackRecordingService iTrackRecordingServiceMock = EasyMock
.createStrictMock(ITrackRecordingService.class);
try {
EasyMock.expect(iTrackRecordingServiceMock.startNewTrack()).andReturn(1L);
EasyMock.replay(iTrackRecordingServiceMock);
controlRecordingService.onHandleIntent(intent, iTrackRecordingServiceMock);
EasyMock.verify(iTrackRecordingServiceMock);
} catch (RemoteException e) {
fail();
}
}
/**
* Tests the method
* {@link ControlRecordingService#onHandleIntent(Intent, ITrackRecordingService)}
* to stop a track recording.
*/
@UsesMocks(ITrackRecordingService.class)
public void testStopRecording() {
Intent intent = startControlRecordingService(context.getString(R.string.track_action_end));
ITrackRecordingService iTrackRecordingServiceMock = EasyMock
.createStrictMock(ITrackRecordingService.class);
try {
iTrackRecordingServiceMock.endCurrentTrack();
EasyMock.replay(iTrackRecordingServiceMock);
controlRecordingService.onHandleIntent(intent, iTrackRecordingServiceMock);
EasyMock.verify(iTrackRecordingServiceMock);
} catch (RemoteException e) {
fail();
}
}
/**
* Starts a ControlRecordingService with a specified action.
*
* @param action the action string in the start intent
*/
private Intent startControlRecordingService(String action) {
Intent intent = new Intent(context, ControlRecordingService.class);
intent.setAction(action);
startService(intent);
controlRecordingService = getService();
return intent;
}
}
@@ -0,0 +1,103 @@
/*
* Copyright 2010 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 com.google.android.apps.mytracks.services;
import static com.google.android.testing.mocking.AndroidMock.expect;
import com.google.android.testing.mocking.AndroidMock;
import com.google.android.testing.mocking.UsesMocks;
import android.test.AndroidTestCase;
import java.io.File;
/**
* Tests {@link RemoveTempFilesService}.
*
* @author Sandor Dornbush
*/
public class RemoveTempFilesServiceTest extends AndroidTestCase {
private static final String DIR_NAME = "/tmp";
private static final String FILE_NAME = "foo";
private RemoveTempFilesService service;
@UsesMocks({ File.class, })
protected void setUp() throws Exception {
service = new RemoveTempFilesService();
};
/**
* Tests when the directory doesn't exists.
*/
public void test_noDir() {
File dir = AndroidMock.createMock(File.class, DIR_NAME);
expect(dir.exists()).andStubReturn(false);
AndroidMock.replay(dir);
assertEquals(0, service.cleanTempDirectory(dir));
AndroidMock.verify(dir);
}
/**
* Tests when the directory is empty.
*/
public void test_emptyDir() {
File dir = AndroidMock.createMock(File.class, DIR_NAME);
expect(dir.exists()).andStubReturn(true);
expect(dir.listFiles()).andStubReturn(new File[0]);
AndroidMock.replay(dir);
assertEquals(0, service.cleanTempDirectory(dir));
AndroidMock.verify(dir);
}
/**
* Tests when there is a new file and it shouldn't get deleted.
*/
public void test_newFile() {
File file = AndroidMock.createMock(File.class, DIR_NAME + FILE_NAME);
expect(file.lastModified()).andStubReturn(System.currentTimeMillis());
File dir = AndroidMock.createMock(File.class, DIR_NAME);
expect(dir.exists()).andStubReturn(true);
expect(dir.listFiles()).andStubReturn(new File[] { file });
AndroidMock.replay(dir, file);
assertEquals(0, service.cleanTempDirectory(dir));
AndroidMock.verify(dir, file);
}
/**
* Tests when there is an old file and it should get deleted.
*/
public void test_oldFile() {
File file = AndroidMock.createMock(File.class, DIR_NAME + FILE_NAME);
// qSet to one hour and 1 millisecond later than the current time
expect(file.lastModified()).andStubReturn(System.currentTimeMillis() - 3600001);
expect(file.delete()).andStubReturn(true);
File dir = AndroidMock.createMock(File.class, DIR_NAME);
expect(dir.exists()).andStubReturn(true);
expect(dir.listFiles()).andStubReturn(new File[] { file });
AndroidMock.replay(dir, file);
assertEquals(1, service.cleanTempDirectory(dir));
AndroidMock.verify(dir, file);
}
}
@@ -0,0 +1,65 @@
// Copyright 2012 Google Inc. All Rights Reserved.
package com.google.android.apps.mytracks.services;
import android.app.PendingIntent;
import android.app.Service;
import android.test.ServiceTestCase;
import android.util.Log;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* A {@link TrackRecordingService} that can be used with
* {@link ServiceTestCase}. {@link ServiceTestCase} throws a null pointer
* exception when the service calls
* {@link Service#startForeground(int, android.app.Notification)} and
* {@link Service#stopForeground(boolean)}.
* <p>
* See http://code.google.com/p/android/issues/detail?id=12122
* <p>
* Wrap these two methods in wrappers and override them.
*
* @author Jimmy Shih
*/
public class TestRecordingService extends TrackRecordingService {
private static final String TAG = TestRecordingService.class.getSimpleName();
@Override
protected void startForegroundService(PendingIntent pendingIntent, int messageId) {
try {
Method setForegroundMethod = Service.class.getMethod("setForeground", boolean.class);
setForegroundMethod.invoke(this, true);
} catch (SecurityException e) {
Log.e(TAG, "Unable to start a service in foreground", e);
} catch (NoSuchMethodException e) {
Log.e(TAG, "Unable to start a service in foreground", e);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Unable to start a service in foreground", e);
} catch (IllegalAccessException e) {
Log.e(TAG, "Unable to start a service in foreground", e);
} catch (InvocationTargetException e) {
Log.e(TAG, "Unable to start a service in foreground", e);
}
}
@Override
protected void stopForegroundService() {
try {
Method setForegroundMethod = Service.class.getMethod("setForeground", boolean.class);
setForegroundMethod.invoke(this, false);
} catch (SecurityException e) {
Log.e(TAG, "Unable to start a service in foreground", e);
} catch (NoSuchMethodException e) {
Log.e(TAG, "Unable to start a service in foreground", e);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Unable to start a service in foreground", e);
} catch (IllegalAccessException e) {
Log.e(TAG, "Unable to start a service in foreground", e);
} catch (InvocationTargetException e) {
Log.e(TAG, "Unable to start a service in foreground", e);
}
}
}
@@ -0,0 +1,796 @@
/*
* Copyright 2010 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 com.google.android.apps.mytracks.services;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.MyTracksProvider;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.location.Location;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.provider.Settings;
import android.test.RenamingDelegatingContext;
import android.test.ServiceTestCase;
import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;
import android.test.mock.MockCursor;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
/**
* Tests for the MyTracks track recording service.
* <p>
* TODO: The original class, ServiceTestCase, has a few limitations, e.g. it's
* not possible to properly shutdown the service, unless tearDown() is called,
* which prevents from testing multiple scenarios in a single test (see
* runFunctionTest for more details).
*
* @author Bartlomiej Niechwiej
*/
public class TrackRecordingServiceTest extends ServiceTestCase<TestRecordingService> {
private Context context;
private MyTracksProviderUtils providerUtils;
/*
* In order to support starting and binding to the service in the same unit
* test, we provide a workaround, as the original class doesn't allow to bind
* after the service has been previously started.
*/
private boolean bound;
private Intent serviceIntent;
public TrackRecordingServiceTest() {
super(TestRecordingService.class);
}
/**
* A context wrapper with the user provided {@link ContentResolver}. TODO:
* Move to test utils package.
*/
public static class MockContext extends ContextWrapper {
private final ContentResolver contentResolver;
public MockContext(ContentResolver contentResolver, Context base) {
super(base);
this.contentResolver = contentResolver;
}
@Override
public ContentResolver getContentResolver() {
return contentResolver;
}
}
@Override
protected IBinder bindService(Intent intent) {
if (getService() != null) {
if (bound) {
throw new IllegalStateException("Service: " + getService() + " is already bound");
}
bound = true;
serviceIntent = intent.cloneFilter();
return getService().onBind(intent);
} else {
return super.bindService(intent);
}
}
@Override
protected void shutdownService() {
if (bound) {
assertNotNull(getService());
getService().onUnbind(serviceIntent);
bound = false;
}
super.shutdownService();
}
@Override
protected void setUp() throws Exception {
super.setUp();
/*
* Create a mock context that uses a mock content resolver and a renaming
* delegating context.
*/
MockContentResolver mockContentResolver = new MockContentResolver();
RenamingDelegatingContext renamingDelegatingContext = new RenamingDelegatingContext(
getContext(), getContext(), "test.");
context = new MockContext(mockContentResolver, renamingDelegatingContext);
// Set up the mock content resolver
MyTracksProvider myTracksProvider = new MyTracksProvider();
myTracksProvider.attachInfo(context, null);
mockContentResolver.addProvider(MyTracksProviderUtils.AUTHORITY, myTracksProvider);
MockContentProvider settingsProvider = new MockContentProvider(context) {
@Override
public Bundle call(String method, String arg, Bundle extras) {
return null;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
return null;
}
};
mockContentResolver.addProvider(Settings.AUTHORITY, settingsProvider);
MockContentProvider googleSettingsProvider = new MockContentProvider(context) {
@Override
public Bundle call(String method, String arg, Bundle extras) {
return null;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
MockCursor mockCursor = new MockCursor() {
@Override
public int getCount() {
return 1;
}
@Override
public boolean moveToNext() {
return true;
}
@Override
public String getString(int columnIndex) {
return MyTracksLocationManager.USE_LOCATION_FOR_SERVICES_ON;
}
@Override
public void close() {}
};
return mockCursor;
}
};
mockContentResolver.addProvider("com.google.settings", googleSettingsProvider);
// Set the context
setContext(context);
providerUtils = MyTracksProviderUtils.Factory.get(context);
SharedPreferences sharedPreferences = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
// Let's use default values.
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(sharedPreferences.edit().clear());
// Disable auto resume by default.
updateAutoResumePrefs(PreferencesUtils.AUTO_RESUME_TRACK_CURRENT_RETRY_DEFAULT, 0);
// No recording track.
PreferencesUtils.setLong(
context, R.string.recording_track_id_key, PreferencesUtils.RECORDING_TRACK_ID_DEFAULT);
}
@SmallTest
public void testStartable() {
startService(createStartIntent());
assertNotNull(getService());
}
@MediumTest
public void testBindable() {
IBinder service = bindService(createStartIntent());
assertNotNull(service);
}
@MediumTest
public void testResumeAfterReboot_shouldResume() throws Exception {
// Insert a dummy track and mark it as recording track.
createDummyTrack(123L, System.currentTimeMillis(), true);
// Clear the number of attempts and set the timeout to 10 min.
updateAutoResumePrefs(PreferencesUtils.AUTO_RESUME_TRACK_CURRENT_RETRY_DEFAULT,
PreferencesUtils.AUTO_RESUME_TRACK_TIMEOUT_DEFAULT);
// Start the service in "resume" mode (simulates the on-reboot action).
Intent startIntent = createStartIntent();
startIntent.putExtra(TrackRecordingService.RESUME_TRACK_EXTRA_NAME, true);
startService(startIntent);
assertNotNull(getService());
// We expect to resume the previous track.
assertTrue(getService().isRecording());
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertEquals(123L, service.getRecordingTrackId());
}
/*
* TODO: shutdownService() has a bug and doesn't set mServiceCreated to false,
* thus preventing from a second call to onCreate(). Report the bug to Android
* team. Until then, the following tests and checks must be commented out.
*
* TODO: If fixed, remove "disabled" prefix from the test name.
*/
@MediumTest
public void disabledTestResumeAfterReboot_simulateReboot() throws Exception {
updateAutoResumePrefs(PreferencesUtils.AUTO_RESUME_TRACK_CURRENT_RETRY_DEFAULT,
PreferencesUtils.AUTO_RESUME_TRACK_TIMEOUT_DEFAULT);
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertFalse(service.isRecording());
// Simulate recording a track.
long id = service.startNewTrack();
assertTrue(service.isRecording());
assertEquals(id, service.getRecordingTrackId());
shutdownService();
assertEquals(id, PreferencesUtils.getLong(context, R.string.recording_track_id_key));
// Start the service in "resume" mode (simulates the on-reboot action).
Intent startIntent = createStartIntent();
startIntent.putExtra(TrackRecordingService.RESUME_TRACK_EXTRA_NAME, true);
startService(startIntent);
assertNotNull(getService());
assertTrue(getService().isRecording());
}
@MediumTest
public void testResumeAfterReboot_noRecordingTrack() throws Exception {
// Insert a dummy track and mark it as recording track.
createDummyTrack(123L, System.currentTimeMillis(), false);
// Clear the number of attempts and set the timeout to 10 min.
updateAutoResumePrefs(PreferencesUtils.AUTO_RESUME_TRACK_CURRENT_RETRY_DEFAULT,
PreferencesUtils.AUTO_RESUME_TRACK_TIMEOUT_DEFAULT);
// Start the service in "resume" mode (simulates the on-reboot action).
Intent startIntent = createStartIntent();
startIntent.putExtra(TrackRecordingService.RESUME_TRACK_EXTRA_NAME, true);
startService(startIntent);
assertNotNull(getService());
// We don't expect to resume the previous track, because it was stopped.
assertFalse(getService().isRecording());
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertEquals(-1L, service.getRecordingTrackId());
}
@MediumTest
public void testResumeAfterReboot_expiredTrack() throws Exception {
// Insert a dummy track last updated 20 min ago.
createDummyTrack(123L, System.currentTimeMillis() - 20 * 60 * 1000, true);
// Clear the number of attempts and set the timeout to 10 min.
updateAutoResumePrefs(PreferencesUtils.AUTO_RESUME_TRACK_CURRENT_RETRY_DEFAULT,
PreferencesUtils.AUTO_RESUME_TRACK_TIMEOUT_DEFAULT);
// Start the service in "resume" mode (simulates the on-reboot action).
Intent startIntent = createStartIntent();
startIntent.putExtra(TrackRecordingService.RESUME_TRACK_EXTRA_NAME, true);
startService(startIntent);
assertNotNull(getService());
// We don't expect to resume the previous track, because it has expired.
assertFalse(getService().isRecording());
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertEquals(-1L, service.getRecordingTrackId());
}
@MediumTest
public void testResumeAfterReboot_tooManyAttempts() throws Exception {
// Insert a dummy track.
createDummyTrack(123L, System.currentTimeMillis(), true);
// Set the number of attempts to max.
updateAutoResumePrefs(TrackRecordingService.MAX_AUTO_RESUME_TRACK_RETRY_ATTEMPTS,
PreferencesUtils.AUTO_RESUME_TRACK_TIMEOUT_DEFAULT);
// Start the service in "resume" mode (simulates the on-reboot action).
Intent startIntent = createStartIntent();
startIntent.putExtra(TrackRecordingService.RESUME_TRACK_EXTRA_NAME, true);
startService(startIntent);
assertNotNull(getService());
// We don't expect to resume the previous track, because there were already
// too many attempts.
assertFalse(getService().isRecording());
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertEquals(-1L, service.getRecordingTrackId());
}
@MediumTest
public void testRecording_noTracks() throws Exception {
List<Track> tracks = providerUtils.getAllTracks();
assertTrue(tracks.isEmpty());
ITrackRecordingService service = bindAndGetService(createStartIntent());
// Test if we start in no-recording mode by default.
assertFalse(service.isRecording());
assertEquals(-1L, service.getRecordingTrackId());
}
@MediumTest
public void testRecording_oldTracks() throws Exception {
createDummyTrack(123L, -1L, false);
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertFalse(service.isRecording());
assertEquals(-1L, service.getRecordingTrackId());
}
@MediumTest
public void testRecording_orphanedRecordingTrack() throws Exception {
// Just set recording track to a bogus value.
PreferencesUtils.setLong(context, R.string.recording_track_id_key, 256L);
// Make sure that the service will not start recording and will clear
// the bogus track.
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertFalse(service.isRecording());
assertEquals(-1L, service.getRecordingTrackId());
}
/**
* Synchronous/waitable broadcast receiver to be used in testing.
*/
private class BlockingBroadcastReceiver extends BroadcastReceiver {
private static final long MAX_WAIT_TIME_MS = 10000;
private List<Intent> receivedIntents = new ArrayList<Intent>();
public List<Intent> getReceivedIntents() {
return receivedIntents;
}
@Override
public void onReceive(Context ctx, Intent intent) {
Log.d("MyTracksTest", "Got broadcast: " + intent);
synchronized (receivedIntents) {
receivedIntents.add(intent);
receivedIntents.notifyAll();
}
}
public boolean waitUntilReceived(int receiveCount) {
long deadline = System.currentTimeMillis() + MAX_WAIT_TIME_MS;
synchronized (receivedIntents) {
while (receivedIntents.size() < receiveCount) {
try {
// Wait releases synchronized lock until it returns
receivedIntents.wait(500);
} catch (InterruptedException e) {
// Do nothing
}
if (System.currentTimeMillis() > deadline) {
return false;
}
}
}
return true;
}
}
@MediumTest
public void testStartNewTrack_noRecording() throws Exception {
// NOTICE: due to the way Android permissions work, if this fails,
// uninstall the test apk then retry - the test must be installed *after*
// My Tracks (go figure).
// Reference: http://code.google.com/p/android/issues/detail?id=5521
BlockingBroadcastReceiver startReceiver = new BlockingBroadcastReceiver();
String startAction = context.getString(R.string.track_started_broadcast_action);
context.registerReceiver(startReceiver, new IntentFilter(startAction));
List<Track> tracks = providerUtils.getAllTracks();
assertTrue(tracks.isEmpty());
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertFalse(service.isRecording());
long id = service.startNewTrack();
assertTrue(id >= 0);
assertTrue(service.isRecording());
Track track = providerUtils.getTrack(id);
assertNotNull(track);
assertEquals(id, track.getId());
assertEquals(PreferencesUtils.getString(
context, R.string.default_activity_key, PreferencesUtils.DEFAULT_ACTIVITY_DEFAULT),
track.getCategory());
assertEquals(id, PreferencesUtils.getLong(context, R.string.recording_track_id_key));
assertEquals(id, service.getRecordingTrackId());
// Verify that the start broadcast was received.
assertTrue(startReceiver.waitUntilReceived(1));
List<Intent> receivedIntents = startReceiver.getReceivedIntents();
assertEquals(1, receivedIntents.size());
Intent broadcastIntent = receivedIntents.get(0);
assertEquals(startAction, broadcastIntent.getAction());
assertEquals(id,
broadcastIntent.getLongExtra(context.getString(R.string.track_id_broadcast_extra), -1L));
context.unregisterReceiver(startReceiver);
}
@MediumTest
public void testStartNewTrack_alreadyRecording() throws Exception {
createDummyTrack(123L, -1L, true);
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertTrue(service.isRecording());
// Starting a new track when there is a recording should just return -1L.
long newTrack = service.startNewTrack();
assertEquals(-1L, newTrack);
assertEquals(123L, PreferencesUtils.getLong(context, R.string.recording_track_id_key));
assertEquals(123L, service.getRecordingTrackId());
}
@MediumTest
public void testEndCurrentTrack_alreadyRecording() throws Exception {
// See comment above if this fails randomly.
BlockingBroadcastReceiver stopReceiver = new BlockingBroadcastReceiver();
String stopAction = context.getString(R.string.track_stopped_broadcast_action);
context.registerReceiver(stopReceiver, new IntentFilter(stopAction));
createDummyTrack(123L, -1L, true);
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertTrue(service.isRecording());
// End the current track.
service.endCurrentTrack();
assertFalse(service.isRecording());
assertEquals(PreferencesUtils.RECORDING_TRACK_ID_DEFAULT,
PreferencesUtils.getLong(context, R.string.recording_track_id_key));
assertEquals(PreferencesUtils.RECORDING_TRACK_ID_DEFAULT, service.getRecordingTrackId());
// Verify that the stop broadcast was received.
assertTrue(stopReceiver.waitUntilReceived(1));
List<Intent> receivedIntents = stopReceiver.getReceivedIntents();
assertEquals(1, receivedIntents.size());
Intent broadcastIntent = receivedIntents.get(0);
assertEquals(stopAction, broadcastIntent.getAction());
assertEquals(123L,
broadcastIntent.getLongExtra(context.getString(R.string.track_id_broadcast_extra), -1L));
context.unregisterReceiver(stopReceiver);
}
@MediumTest
public void testEndCurrentTrack_noRecording() throws Exception {
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertFalse(service.isRecording());
/*
* Ending the current track when there is no recording should not result in
* any error.
*/
service.endCurrentTrack();
assertEquals(PreferencesUtils.RECORDING_TRACK_ID_DEFAULT,
PreferencesUtils.getLong(context, R.string.recording_track_id_key));
assertEquals(PreferencesUtils.RECORDING_TRACK_ID_DEFAULT, service.getRecordingTrackId());
}
@MediumTest
public void testIntegration_completeRecordingSession() throws Exception {
List<Track> tracks = providerUtils.getAllTracks();
assertTrue(tracks.isEmpty());
fullRecordingSession();
}
@MediumTest
public void testInsertStatisticsMarker_noRecordingTrack() throws Exception {
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertFalse(service.isRecording());
long waypointId = service.insertWaypoint(WaypointCreationRequest.DEFAULT_STATISTICS);
assertEquals(-1L, waypointId);
}
@MediumTest
public void testInsertStatisticsMarker_validLocation() throws Exception {
createDummyTrack(123L, -1L, true);
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertTrue(service.isRecording());
assertFalse(service.isPaused());
insertLocation(service);
assertEquals(1, service.insertWaypoint(WaypointCreationRequest.DEFAULT_STATISTICS));
assertEquals(2, service.insertWaypoint(WaypointCreationRequest.DEFAULT_STATISTICS));
Waypoint wpt = providerUtils.getWaypoint(2);
assertEquals(getContext().getString(R.string.marker_statistics_icon_url), wpt.getIcon());
assertEquals(getContext().getString(R.string.marker_split_name_format, 1), wpt.getName());
assertEquals(WaypointType.STATISTICS, wpt.getType());
assertEquals(123L, wpt.getTrackId());
assertEquals(0.0, wpt.getLength());
assertNotNull(wpt.getLocation());
assertNotNull(wpt.getTripStatistics());
// TODO check the rest of the params.
// TODO: Check waypoint 2.
}
@MediumTest
public void testInsertWaypointMarker_noRecordingTrack() throws Exception {
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertFalse(service.isRecording());
long waypointId = service.insertWaypoint(WaypointCreationRequest.DEFAULT_WAYPOINT);
assertEquals(-1L, waypointId);
}
@MediumTest
public void testInsertWaypointMarker_validWaypoint() throws Exception {
createDummyTrack(123L, -1L, true);
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertTrue(service.isRecording());
insertLocation(service);
assertEquals(1, service.insertWaypoint(WaypointCreationRequest.DEFAULT_WAYPOINT));
Waypoint wpt = providerUtils.getWaypoint(1);
assertEquals(getContext().getString(R.string.marker_waypoint_icon_url), wpt.getIcon());
assertEquals(getContext().getString(R.string.marker_name_format, 1), wpt.getName());
assertEquals(WaypointType.WAYPOINT, wpt.getType());
assertEquals(123L, wpt.getTrackId());
assertEquals(0.0, wpt.getLength());
assertNotNull(wpt.getLocation());
assertNull(wpt.getTripStatistics());
}
@MediumTest
public void testWithProperties_voiceFrequencyDefault() throws Exception {
PreferencesUtils.setInt(
context, R.string.voice_frequency_key, PreferencesUtils.VOICE_FREQUENCY_DEFAULT);
fullRecordingSession();
}
@MediumTest
public void testWithProperties_voiceFrequencyByDistance() throws Exception {
PreferencesUtils.setInt(context, R.string.voice_frequency_key, -1);
fullRecordingSession();
}
@MediumTest
public void testWithProperties_voiceFrequencyByTime() throws Exception {
PreferencesUtils.setInt(context, R.string.voice_frequency_key, 1);
fullRecordingSession();
}
@MediumTest
public void testWithProperties_maxRecordingDistanceDefault() throws Exception {
PreferencesUtils.setInt(context, R.string.max_recording_distance_key,
PreferencesUtils.MAX_RECORDING_DISTANCE_DEFAULT);
fullRecordingSession();
}
@MediumTest
public void testWithProperties_maxRecordingDistance() throws Exception {
PreferencesUtils.setInt(context, R.string.max_recording_distance_key, 50);
fullRecordingSession();
}
@MediumTest
public void testWithProperties_minRecordingDistanceDefault() throws Exception {
PreferencesUtils.setInt(context, R.string.min_recording_distance_key,
PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT);
fullRecordingSession();
}
@MediumTest
public void testWithProperties_minRecordingDistance() throws Exception {
PreferencesUtils.setInt(context, R.string.min_recording_distance_key, 2);
fullRecordingSession();
}
@MediumTest
public void testWithProperties_splitFrequencyDefault() throws Exception {
PreferencesUtils.setInt(
context, R.string.split_frequency_key, PreferencesUtils.SPLIT_FREQUENCY_DEFAULT);
fullRecordingSession();
}
@MediumTest
public void testWithProperties_splitFrequencyByDistance() throws Exception {
PreferencesUtils.setInt(context, R.string.split_frequency_key, -1);
fullRecordingSession();
}
@MediumTest
public void testWithProperties_splitFrequencyByTime() throws Exception {
PreferencesUtils.setInt(context, R.string.split_frequency_key, 1);
fullRecordingSession();
}
@MediumTest
public void testWithProperties_metricUnitsDefault() throws Exception {
PreferencesUtils.setBoolean(
context, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT);
fullRecordingSession();
}
@MediumTest
public void testWithProperties_metricUnitsDisabled() throws Exception {
PreferencesUtils.setBoolean(context, R.string.metric_units_key, false);
fullRecordingSession();
}
@MediumTest
public void testWithProperties_minRecordingIntervalDefault() throws Exception {
PreferencesUtils.setInt(context, R.string.min_recording_interval_key,
PreferencesUtils.MIN_RECORDING_INTERVAL_DEFAULT);
fullRecordingSession();
}
@MediumTest
public void testWithProperties_minRecordingInterval() throws Exception {
PreferencesUtils.setInt(context, R.string.min_recording_interval_key, 2);
fullRecordingSession();
}
@MediumTest
public void testWithProperties_minRequiredAccuracyDefault() throws Exception {
PreferencesUtils.setInt(context, R.string.min_required_accuracy_key,
PreferencesUtils.MIN_REQUIRED_ACCURACY_DEFAULT);
fullRecordingSession();
}
@MediumTest
public void testWithProperties_minRequiredAccuracy() throws Exception {
PreferencesUtils.setInt(context, R.string.min_required_accuracy_key, 500);
fullRecordingSession();
}
@MediumTest
public void testWithProperties_sensorTypeDefault() throws Exception {
PreferencesUtils.setString(
context, R.string.sensor_type_key, PreferencesUtils.SENSOR_TYPE_DEFAULT);
fullRecordingSession();
}
@MediumTest
public void testWithProperties_sensorTypeZephyr() throws Exception {
PreferencesUtils.setString(
context, R.string.sensor_type_key, context.getString(R.string.sensor_type_value_zephyr));
fullRecordingSession();
}
private ITrackRecordingService bindAndGetService(Intent intent) {
ITrackRecordingService service = ITrackRecordingService.Stub.asInterface(bindService(intent));
assertNotNull(service);
return service;
}
private Track createDummyTrack(long id, long stopTime, boolean isRecording) {
Track dummyTrack = new Track();
dummyTrack.setId(id);
dummyTrack.setName("Dummy Track");
TripStatistics tripStatistics = new TripStatistics();
tripStatistics.setStopTime(stopTime);
dummyTrack.setTripStatistics(tripStatistics);
addTrack(dummyTrack, isRecording);
return dummyTrack;
}
private void updateAutoResumePrefs(int attempts, int timeoutMins) {
PreferencesUtils.setInt(context, R.string.auto_resume_track_current_retry_key, attempts);
PreferencesUtils.setInt(context, R.string.auto_resume_track_timeout_key, timeoutMins);
}
private Intent createStartIntent() {
Intent startIntent = new Intent();
startIntent.setClass(context, TrackRecordingService.class);
return startIntent;
}
private void addTrack(Track track, boolean isRecording) {
assertTrue(track.getId() >= 0);
providerUtils.insertTrack(track);
assertEquals(track.getId(), providerUtils.getTrack(track.getId()).getId());
PreferencesUtils.setLong(context, R.string.recording_track_id_key,
isRecording ? track.getId() : PreferencesUtils.RECORDING_TRACK_ID_DEFAULT);
PreferencesUtils.setBoolean(context, R.string.recording_track_paused_key, !isRecording);
}
private void fullRecordingSession() throws Exception {
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertFalse(service.isRecording());
// Start a track.
long id = service.startNewTrack();
assertTrue(id >= 0);
assertTrue(service.isRecording());
Track track = providerUtils.getTrack(id);
assertNotNull(track);
assertEquals(id, track.getId());
assertEquals(id, PreferencesUtils.getLong(context, R.string.recording_track_id_key));
assertEquals(id, service.getRecordingTrackId());
// Insert a few points, markers and statistics.
long startTime = System.currentTimeMillis();
for (int i = 0; i < 30; i++) {
Location loc = new Location("gps");
loc.setLongitude(35.0f + i / 10.0f);
loc.setLatitude(45.0f - i / 5.0f);
loc.setAccuracy(5);
loc.setSpeed(10);
loc.setTime(startTime + i * 10000);
loc.setBearing(3.0f);
service.insertTrackPoint(loc);
if (i % 10 == 0) {
service.insertWaypoint(WaypointCreationRequest.DEFAULT_STATISTICS);
} else if (i % 7 == 0) {
service.insertWaypoint(WaypointCreationRequest.DEFAULT_WAYPOINT);
}
}
// Stop the track. Validate if it has correct data.
service.endCurrentTrack();
assertFalse(service.isRecording());
assertEquals(-1L, service.getRecordingTrackId());
track = providerUtils.getTrack(id);
assertNotNull(track);
assertEquals(id, track.getId());
TripStatistics tripStatistics = track.getTripStatistics();
assertNotNull(tripStatistics);
assertTrue(tripStatistics.getStartTime() > 0);
assertTrue(tripStatistics.getStopTime() >= tripStatistics.getStartTime());
}
/**
* Inserts a location and waits for 100ms.
*
* @param trackRecordingService the track recording service
*/
private void insertLocation(ITrackRecordingService trackRecordingService)
throws RemoteException, InterruptedException {
Location location = new Location("gps");
location.setLongitude(35.0f);
location.setLatitude(45.0f);
location.setAccuracy(5);
location.setSpeed(10);
location.setTime(System.currentTimeMillis());
location.setBearing(3.0f);
trackRecordingService.insertTrackPoint(location);
Thread.sleep(200);
}
}
@@ -0,0 +1,69 @@
package com.google.android.apps.mytracks.services.sensors;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import junit.framework.TestCase;
public class PolarMessageParserTest extends TestCase {
PolarMessageParser parser = new PolarMessageParser();
// A complete and valid Polar HxM packet
// FE08F701D1001104FE08F702D1001104
private final byte[] originalBuf =
{(byte) 0xFE, 0x08, (byte) 0xF7, 0x01, (byte) 0xD1, 0x00, 0x11, 0x04, (byte) 0xFE, 0x08,
(byte) 0xF7, 0x02, (byte) 0xD1, 0x00, 0x11, 0x04};
private byte[] buf;
public void setUp() {
buf = ApiAdapterFactory.getApiAdapter().copyByteArray(originalBuf, 0, originalBuf.length);
}
public void testIsValid() {
assertTrue(parser.isValid(buf));
}
public void testIsValid_invalidHeader() {
// Invalidate header.
buf[0] = 0x03;
assertFalse(parser.isValid(buf));
}
public void testIsValid_invalidCheckbyte() {
// Invalidate checkbyte.
buf[2] = 0x03;
assertFalse(parser.isValid(buf));
}
public void testIsValid_invalidSequence() {
// Invalidate sequence.
buf[3] = 0x11;
assertFalse(parser.isValid(buf));
}
public void testParseBuffer() {
buf[5] = 70;
Sensor.SensorDataSet sds = parser.parseBuffer(buf);
assertTrue(sds.hasHeartRate());
assertTrue(sds.getHeartRate().getState() == Sensor.SensorState.SENDING);
assertEquals(70, sds.getHeartRate().getValue());
}
public void testFindNextAlignment_offset() {
// The first 4 bytes are garbage
buf = new byte[originalBuf.length + 4];
buf[0] = 4;
buf[1] = 2;
buf[2] = 4;
buf[3] = 2;
// Then the valid message.
System.arraycopy(originalBuf, 0, buf, 4, originalBuf.length);
assertEquals(4, parser.findNextAlignment(buf));
}
public void testFindNextAlignment_invalid() {
buf[0] = 0;
assertEquals(-1, parser.findNextAlignment(buf));
}
}
@@ -0,0 +1,47 @@
package com.google.android.apps.mytracks.services.sensors;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
import android.content.Context;
import android.content.SharedPreferences;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
public class SensorManagerFactoryTest extends AndroidTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
SharedPreferences sharedPreferences = getContext().getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
// Let's use default values.
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(sharedPreferences.edit().clear());
}
@SmallTest
public void testDefaultSettings() throws Exception {
assertNull(SensorManagerFactory.getSystemSensorManager(getContext()));
}
@SmallTest
public void testCreateZephyr() throws Exception {
assertClassForName(ZephyrSensorManager.class, R.string.sensor_type_value_zephyr);
}
@SmallTest
public void testCreatePolar() throws Exception {
assertClassForName(PolarSensorManager.class, R.string.sensor_type_value_polar);
}
private void assertClassForName(Class<?> c, int i) {
PreferencesUtils.setString(getContext(), R.string.sensor_type_key, getContext().getString(i));
SensorManager sm = SensorManagerFactory.getSystemSensorManager(getContext());
assertNotNull(sm);
assertTrue(c.isInstance(sm));
SensorManagerFactory.releaseSystemSensorManager();
}
}
@@ -0,0 +1,63 @@
/*
* Copyright 2011 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 com.google.android.apps.mytracks.services.sensors;
import junit.framework.TestCase;
/**
* @author Dominik Rottsches
*/
public class StrideReadingsTest extends TestCase {
public void testNoReadingOnStartup() {
StrideReadings strideReadings = new StrideReadings();
assertEquals(StrideReadings.CADENCE_NOT_AVAILABLE, strideReadings.getCadence());
}
public void testAverageCadenceAvailable() {
StrideReadings strideReadings = new StrideReadings();
// 2 steps / second => Cadence is 120 / minute
for (int i = 1; i <= 30; i++) {
strideReadings.updateStrideReading(i*2);
if (i >= StrideReadings.MIN_READINGS_FOR_AVERAGE) {
assertEquals(120, strideReadings.getCadence());
} else {
assertEquals(StrideReadings.CADENCE_NOT_AVAILABLE, strideReadings.getCadence());
}
}
}
/**
* Tests for correct calculation after rolling over at 128 strides,
* just like the HxM seems to do it.
*/
public void testRollover() {
StrideReadings strideReadings = new StrideReadings();
// 1 step per second => Cadence is 60 / minute
// Updating readings counting upwards from initialStrides -
// initialStrides set to a value below 128 to ensure rollover.
int initialStrides = 128 - StrideReadings.NUM_READINGS_FOR_AVERAGE - 5;
for (int i = 1; i <= StrideReadings.NUM_READINGS_FOR_AVERAGE + 10; i++) {
strideReadings.updateStrideReading((initialStrides + i) % 128);
if (i >= StrideReadings.MIN_READINGS_FOR_AVERAGE) {
assertEquals(60, strideReadings.getCadence());
} else {
assertEquals(StrideReadings.CADENCE_NOT_AVAILABLE, strideReadings.getCadence());
}
}
}
}
@@ -0,0 +1,55 @@
package com.google.android.apps.mytracks.services.sensors;
import com.google.android.apps.mytracks.content.Sensor;
import junit.framework.TestCase;
public class ZephyrMessageParserTest extends TestCase {
ZephyrMessageParser parser = new ZephyrMessageParser();
public void testIsValid() {
byte[] smallBuf = new byte[59];
assertFalse(parser.isValid(smallBuf));
// A complete and valid Zephyr HxM packet
byte[] buf = { 2,38,55,26,0,49,101,80,0,49,98,100,42,113,120,-53,-24,-60,-123,-61,117,-69,42,-75,74,-78,51,-79,27,-83,28,-88,28,-93,29,-98,25,-103,26,-108,26,-113,59,-118,0,0,0,0,0,0,-22,3,125,1,48,0,96,4,30,0 };
// Make buffer invalid
buf[0] = buf[58] = buf[59] = 0;
assertFalse(parser.isValid(buf));
buf[0] = 0x02;
assertFalse(parser.isValid(buf));
buf[58] = 0x1E;
assertFalse(parser.isValid(buf));
buf[59] = 0x03;
assertTrue(parser.isValid(buf));
}
public void testParseBuffer() {
byte[] buf = new byte[60];
// Heart Rate (-1 =^ 255 unsigned byte)
buf[12] = -1;
// Battery Level
buf[11] = 51;
// Cadence (=^ 255*16 strides/min)
buf[56] = -1;
buf[57] = 15;
Sensor.SensorDataSet sds = parser.parseBuffer(buf);
assertTrue(sds.hasHeartRate());
assertTrue(sds.getHeartRate().getState() == Sensor.SensorState.SENDING);
assertEquals(255, sds.getHeartRate().getValue());
assertTrue(sds.hasBatteryLevel());
assertTrue(sds.getBatteryLevel().getState() == Sensor.SensorState.SENDING);
assertEquals(51, sds.getBatteryLevel().getValue());
assertTrue(sds.hasCadence());
assertTrue(sds.getCadence().getState() == Sensor.SensorState.SENDING);
assertEquals(255, sds.getCadence().getValue());
}
public void testFindNextAlignment() {
byte[] buf = new byte[60];
assertEquals(-1, parser.findNextAlignment(buf));
buf[10] = 0x03;
buf[11] = 0x02;
assertEquals(10, parser.findNextAlignment(buf));
}
}
@@ -0,0 +1,33 @@
/*
* Copyright 2010 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 com.google.android.apps.mytracks.services.tasks;
import android.test.AndroidTestCase;
/**
* Tests for {@link AnnouncementPeriodicTaskFactory}.
* These tests require Donut+ to run.
*
* @author Rodrigo Damazio
*/
public class AnnouncementPeriodicTaskFactoryTest extends AndroidTestCase {
public void testCreate() {
PeriodicTaskFactory factory = new AnnouncementPeriodicTaskFactory();
PeriodicTask task = factory.create(getContext());
assertTrue(task instanceof AnnouncementPeriodicTask);
}
}
@@ -0,0 +1,533 @@
/*
* Copyright 2010 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 com.google.android.apps.mytracks.services.tasks;
import static com.google.android.testing.mocking.AndroidMock.capture;
import static com.google.android.testing.mocking.AndroidMock.eq;
import static com.google.android.testing.mocking.AndroidMock.expect;
import static com.google.android.testing.mocking.AndroidMock.same;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.testing.mocking.AndroidMock;
import com.google.android.testing.mocking.UsesMocks;
import android.content.Context;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;
import android.speech.tts.TextToSpeech.OnUtteranceCompletedListener;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.test.AndroidTestCase;
import java.util.HashMap;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean;
import org.easymock.Capture;
import org.easymock.EasyMock;
/**
* Tests for {@link AnnouncementPeriodicTask}.
* WARNING: I'm not responsible if your eyes start bleeding while reading this
* code. You have been warned. It's still better than no test, though.
*
* @author Rodrigo Damazio
*/
public class AnnouncementPeriodicTaskTest extends AndroidTestCase {
// Use something other than our hardcoded value
private static final Locale DEFAULT_LOCALE = Locale.KOREAN;
private static final String ANNOUNCEMENT = "I can haz cheeseburger?";
private Locale oldDefaultLocale;
private AnnouncementPeriodicTask task;
private AnnouncementPeriodicTask mockTask;
private Capture<OnInitListener> initListenerCapture;
private Capture<PhoneStateListener> phoneListenerCapture;
private TextToSpeechDelegate ttsDelegate;
private TextToSpeechInterface tts;
/**
* Mockable interface that we delegate TTS calls to.
*/
interface TextToSpeechInterface {
int addEarcon(String earcon, String packagename, int resourceId);
int addEarcon(String earcon, String filename);
int addSpeech(String text, String packagename, int resourceId);
int addSpeech(String text, String filename);
boolean areDefaultsEnforced();
String getDefaultEngine();
Locale getLanguage();
int isLanguageAvailable(Locale loc);
boolean isSpeaking();
int playEarcon(String earcon, int queueMode,
HashMap<String, String> params);
int playSilence(long durationInMs, int queueMode,
HashMap<String, String> params);
int setEngineByPackageName(String enginePackageName);
int setLanguage(Locale loc);
int setOnUtteranceCompletedListener(OnUtteranceCompletedListener listener);
int setPitch(float pitch);
int setSpeechRate(float speechRate);
void shutdown();
int speak(String text, int queueMode, HashMap<String, String> params);
int stop();
int synthesizeToFile(String text, HashMap<String, String> params,
String filename);
}
/**
* Subclass of {@link TextToSpeech} which delegates calls to the interface
* above.
* The logic here is stupid and the author is ashamed of having to write it
* like this, but basically the issue is that TextToSpeech cannot be mocked
* without running its constructor, its constructor runs async operations
* which call other methods (and then if the methods are part of a mock we'd
* have to set a behavior, but we can't 'cause the object hasn't been fully
* built yet).
* The logic is that calls made during the constructor (when tts is not yet
* set) will go up to the original class, but after tts is set we'll forward
* them all to the mock.
*/
private class TextToSpeechDelegate
extends TextToSpeech implements TextToSpeechInterface {
public TextToSpeechDelegate(Context context, OnInitListener listener) {
super(context, listener);
}
@Override
public int addEarcon(String earcon, String packagename, int resourceId) {
if (tts == null) {
return super.addEarcon(earcon, packagename, resourceId);
}
return tts.addEarcon(earcon, packagename, resourceId);
}
@Override
public int addEarcon(String earcon, String filename) {
if (tts == null) {
return super.addEarcon(earcon, filename);
}
return tts.addEarcon(earcon, filename);
}
@Override
public int addSpeech(String text, String packagename, int resourceId) {
if (tts == null) {
return super.addSpeech(text, packagename, resourceId);
}
return tts.addSpeech(text, packagename, resourceId);
}
@Override
public int addSpeech(String text, String filename) {
if (tts == null) {
return super.addSpeech(text, filename);
}
return tts.addSpeech(text, filename);
}
@Override
public Locale getLanguage() {
if (tts == null) {
return super.getLanguage();
}
return tts.getLanguage();
}
@Override
public int isLanguageAvailable(Locale loc) {
if (tts == null) {
return super.isLanguageAvailable(loc);
}
return tts.isLanguageAvailable(loc);
}
@Override
public boolean isSpeaking() {
if (tts == null) {
return super.isSpeaking();
}
return tts.isSpeaking();
}
@Override
public int playEarcon(String earcon, int queueMode,
HashMap<String, String> params) {
if (tts == null) {
return super.playEarcon(earcon, queueMode, params);
}
return tts.playEarcon(earcon, queueMode, params);
}
@Override
public int playSilence(long durationInMs, int queueMode,
HashMap<String, String> params) {
if (tts == null) {
return super.playSilence(durationInMs, queueMode, params);
}
return tts.playSilence(durationInMs, queueMode, params);
}
@Override
public int setLanguage(Locale loc) {
if (tts == null) {
return super.setLanguage(loc);
}
return tts.setLanguage(loc);
}
@Override
public int setOnUtteranceCompletedListener(
OnUtteranceCompletedListener listener) {
if (tts == null) {
return super.setOnUtteranceCompletedListener(listener);
}
return tts.setOnUtteranceCompletedListener(listener);
}
@Override
public int setPitch(float pitch) {
if (tts == null) {
return super.setPitch(pitch);
}
return tts.setPitch(pitch);
}
@Override
public int setSpeechRate(float speechRate) {
if (tts == null) {
return super.setSpeechRate(speechRate);
}
return tts.setSpeechRate(speechRate);
}
@Override
public void shutdown() {
if (tts == null) {
super.shutdown();
return;
}
tts.shutdown();
}
@Override
public int speak(
String text, int queueMode, HashMap<String, String> params) {
if (tts == null) {
return super.speak(text, queueMode, params);
}
return tts.speak(text, queueMode, params);
}
@Override
public int stop() {
if (tts == null) {
return super.stop();
}
return tts.stop();
}
@Override
public int synthesizeToFile(String text, HashMap<String, String> params,
String filename) {
if (tts == null) {
return super.synthesizeToFile(text, params, filename);
}
return tts.synthesizeToFile(text, params, filename);
}
}
@UsesMocks({
AnnouncementPeriodicTask.class,
StringUtils.class,
})
@Override
protected void setUp() throws Exception {
super.setUp();
oldDefaultLocale = Locale.getDefault();
Locale.setDefault(DEFAULT_LOCALE);
// Eww, the effort required just to mock TextToSpeech is insane
final AtomicBoolean listenerCalled = new AtomicBoolean();
OnInitListener blockingListener = new OnInitListener() {
@Override
public void onInit(int status) {
synchronized (this) {
listenerCalled.set(true);
notify();
}
}
};
ttsDelegate = new TextToSpeechDelegate(getContext(), blockingListener);
// Wait for all async operations done in the constructor to finish.
synchronized (blockingListener) {
while (!listenerCalled.get()) {
// Releases the synchronized lock until we're woken up.
blockingListener.wait();
}
}
// Phew, done, now we can start forwarding calls
tts = AndroidMock.createMock(TextToSpeechInterface.class);
initListenerCapture = new Capture<OnInitListener>();
phoneListenerCapture = new Capture<PhoneStateListener>();
// Create a partial forwarding mock
mockTask = AndroidMock.createMock(AnnouncementPeriodicTask.class, getContext());
task = new AnnouncementPeriodicTask(getContext()) {
@Override
protected TextToSpeech newTextToSpeech(Context ctx,
OnInitListener onInitListener) {
return mockTask.newTextToSpeech(ctx, onInitListener);
}
@Override
protected String getAnnouncement(TripStatistics stats) {
return mockTask.getAnnouncement(stats);
}
@Override
protected void listenToPhoneState(
PhoneStateListener listener, int events) {
mockTask.listenToPhoneState(listener, events);
}
};
}
@Override
protected void tearDown() {
Locale.setDefault(oldDefaultLocale);
}
public void testStart() {
doStart();
OnInitListener ttsInitListener = initListenerCapture.getValue();
assertNotNull(ttsInitListener);
AndroidMock.replay(tts);
ttsInitListener.onInit(TextToSpeech.SUCCESS);
AndroidMock.verify(mockTask, tts);
}
public void testStart_notReady() {
doStart();
OnInitListener ttsInitListener = initListenerCapture.getValue();
assertNotNull(ttsInitListener);
AndroidMock.replay(tts);
ttsInitListener.onInit(TextToSpeech.ERROR);
AndroidMock.verify(mockTask, tts);
}
public void testShutdown() {
// First, start
doStart();
AndroidMock.verify(mockTask);
AndroidMock.reset(mockTask);
// Then, shut down
PhoneStateListener phoneListener = phoneListenerCapture.getValue();
mockTask.listenToPhoneState(
same(phoneListener), eq(PhoneStateListener.LISTEN_NONE));
tts.shutdown();
AndroidMock.replay(mockTask, tts);
task.shutdown();
AndroidMock.verify(mockTask, tts);
}
public void testRun() throws Exception {
// Expect service data calls
TripStatistics stats = new TripStatistics();
// Expect announcement building call
expect(mockTask.getAnnouncement(same(stats))).andStubReturn(ANNOUNCEMENT);
// Put task in "ready" state
startTask(TextToSpeech.SUCCESS);
expect(tts.isLanguageAvailable(DEFAULT_LOCALE)).andStubReturn(TextToSpeech.LANG_AVAILABLE);
expect(tts.setLanguage(DEFAULT_LOCALE)).andReturn(TextToSpeech.LANG_AVAILABLE);
expect(tts.setSpeechRate(AnnouncementPeriodicTask.TTS_SPEECH_RATE)).andReturn(
TextToSpeech.SUCCESS);
expect(tts.setOnUtteranceCompletedListener((OnUtteranceCompletedListener) EasyMock.anyObject()))
.andReturn(0);
// Expect actual announcement call
expect(
tts.speak(eq(ANNOUNCEMENT), eq(TextToSpeech.QUEUE_FLUSH),
eq(AnnouncementPeriodicTask.SPEECH_PARAMS))).andReturn(0);
// Run the announcement
AndroidMock.replay(tts);
task.announce(stats);
AndroidMock.verify(mockTask, tts);
}
public void testRun_notReady() throws Exception {
// Put task in "not ready" state
startTask(TextToSpeech.ERROR);
// Run the announcement
AndroidMock.replay(tts);
task.run(null);
AndroidMock.verify(mockTask, tts);
}
public void testRun_duringCall() throws Exception {
startTask(TextToSpeech.SUCCESS);
expect(tts.isSpeaking()).andStubReturn(false);
// Run the announcement
AndroidMock.replay(tts);
PhoneStateListener phoneListener = phoneListenerCapture.getValue();
phoneListener.onCallStateChanged(TelephonyManager.CALL_STATE_OFFHOOK, null);
task.run(null);
AndroidMock.verify(mockTask, tts);
}
public void testRun_ringWhileSpeaking() throws Exception {
startTask(TextToSpeech.SUCCESS);
expect(tts.isSpeaking()).andStubReturn(true);
expect(tts.stop()).andReturn(TextToSpeech.SUCCESS);
AndroidMock.replay(tts);
// Update the state to ringing - this should stop the current announcement.
PhoneStateListener phoneListener = phoneListenerCapture.getValue();
phoneListener.onCallStateChanged(TelephonyManager.CALL_STATE_RINGING, null);
// Run the announcement - this should do nothing.
task.run(null);
AndroidMock.verify(mockTask, tts);
}
public void testRun_whileRinging() throws Exception {
startTask(TextToSpeech.SUCCESS);
expect(tts.isSpeaking()).andStubReturn(false);
// Run the announcement
AndroidMock.replay(tts);
PhoneStateListener phoneListener = phoneListenerCapture.getValue();
phoneListener.onCallStateChanged(TelephonyManager.CALL_STATE_RINGING, null);
task.run(null);
AndroidMock.verify(mockTask, tts);
}
public void testRun_noService() throws Exception {
startTask(TextToSpeech.SUCCESS);
// Run the announcement
AndroidMock.replay(tts);
task.run(null);
AndroidMock.verify(mockTask, tts);
}
public void testRun_noStats() throws Exception {
// Expect service data calls
startTask(TextToSpeech.SUCCESS);
// Run the announcement
AndroidMock.replay(tts);
task.run(null);
AndroidMock.verify(mockTask, tts);
}
/**
* Tests {@link AnnouncementPeriodicTask#getAnnounceTime(long)} with time zero.
*/
public void testGetAnnounceTime_time_zero() {
long time = 0; // 0 seconds
assertEquals("0 minutes 0 seconds", task.getAnnounceTime(time));
}
/**
* Tests {@link AnnouncementPeriodicTask#getAnnounceTime(long)} with time one.
*/
public void testGetAnnounceTime_time_one() {
long time = 1 * 1000; // 1 second
assertEquals("0 minutes 1 second", task.getAnnounceTime(time));
}
/**
* Tests {@link AnnouncementPeriodicTask#getAnnounceTime(long)} with singular
* numbers with the hour unit.
*/
public void testGetAnnounceTime_singular_has_hour() {
long time = (1 * 60 * 60 * 1000) + (1 * 60 * 1000) + (1 * 1000); // 1 hour 1 minute 1 second
assertEquals("1 hour 1 minute 1 second", task.getAnnounceTime(time));
}
/**
* Tests {@link AnnouncementPeriodicTask#getAnnounceTime(long)} with plural numbers
* with the hour unit.
*/
public void testGetAnnounceTime_plural_has_hour() {
long time = (2 * 60 * 60 * 1000) + (2 * 60 * 1000) + (2 * 1000); // 2 hours 2 minutes 2 seconds
assertEquals("2 hours 2 minutes 2 seconds", task.getAnnounceTime(time));
}
/**
* Tests {@link AnnouncementPeriodicTask#getAnnounceTime(long)} with singular
* numbers without the hour unit.
*/
public void testGetAnnounceTime_singular_no_hour() {
long time = (1 * 60 * 1000) + (1 * 1000); // 1 minute 1 second
assertEquals("1 minute 1 second", task.getAnnounceTime(time));
}
/**
* Tests {@link AnnouncementPeriodicTask#getAnnounceTime(long)} with plural numbers
* without the hour unit.
*/
public void testGetAnnounceTime_plural_no_hour() {
long time = (2 * 60 * 1000) + (2 * 1000); // 2 minutes 2 seconds
assertEquals("2 minutes 2 seconds", task.getAnnounceTime(time));
}
private void startTask(int state) {
AndroidMock.resetToNice(tts);
AndroidMock.replay(tts);
doStart();
OnInitListener ttsInitListener = initListenerCapture.getValue();
ttsInitListener.onInit(state);
AndroidMock.resetToDefault(tts);
}
private void doStart() {
mockTask.listenToPhoneState(capture(phoneListenerCapture),
eq(PhoneStateListener.LISTEN_CALL_STATE));
expect(mockTask.newTextToSpeech(
same(getContext()), capture(initListenerCapture)))
.andStubReturn(ttsDelegate);
AndroidMock.replay(mockTask);
task.start();
}
}
@@ -0,0 +1,117 @@
/*
* Copyright 2009 Google Inc. All Rights Reserved.
*/
package com.google.android.apps.mytracks.stats;
import junit.framework.TestCase;
/**
* Test for the DoubleBuffer class.
*
* @author Sandor Dornbush
*/
public class DoubleBufferTest extends TestCase {
/**
* Tests that the constructor leaves the buffer in a valid state.
*/
public void testConstructor() {
DoubleBuffer buffer = new DoubleBuffer(10);
assertFalse(buffer.isFull());
assertEquals(0.0, buffer.getAverage());
double[] averageAndVariance = buffer.getAverageAndVariance();
assertEquals(0.0, averageAndVariance[0]);
assertEquals(0.0, averageAndVariance[1]);
}
/**
* Simple test with 10 of the same values.
*/
public void testBasic() {
DoubleBuffer buffer = new DoubleBuffer(10);
for (int i = 0; i < 9; i++) {
buffer.setNext(1.0);
assertFalse(buffer.isFull());
assertEquals(1.0, buffer.getAverage());
double[] averageAndVariance = buffer.getAverageAndVariance();
assertEquals(1.0, averageAndVariance[0]);
assertEquals(0.0, averageAndVariance[1]);
}
buffer.setNext(1);
assertTrue(buffer.isFull());
assertEquals(1.0, buffer.getAverage());
double[] averageAndVariance = buffer.getAverageAndVariance();
assertEquals(1.0, averageAndVariance[0]);
assertEquals(0.0, averageAndVariance[1]);
}
/**
* Tests with 5 entries of -10 and 5 entries of 10.
*/
public void testSplit() {
DoubleBuffer buffer = new DoubleBuffer(10);
for (int i = 0; i < 5; i++) {
buffer.setNext(-10);
assertFalse(buffer.isFull());
assertEquals(-10.0, buffer.getAverage());
double[] averageAndVariance = buffer.getAverageAndVariance();
assertEquals(-10.0, averageAndVariance[0]);
assertEquals(0.0, averageAndVariance[1]);
}
for (int i = 1; i < 5; i++) {
buffer.setNext(10);
assertFalse(buffer.isFull());
double expectedAverage = ((i * 10.0) - 50.0) / (i + 5);
assertEquals(buffer.toString(),
expectedAverage, buffer.getAverage(), 0.01);
double[] averageAndVariance = buffer.getAverageAndVariance();
assertEquals(expectedAverage, averageAndVariance[0]);
}
buffer.setNext(10);
assertTrue(buffer.isFull());
assertEquals(0.0, buffer.getAverage());
double[] averageAndVariance = buffer.getAverageAndVariance();
assertEquals(0.0, averageAndVariance[0]);
assertEquals(100.0, averageAndVariance[1]);
}
/**
* Tests that reset leaves the buffer in a valid state.
*/
public void testReset() {
DoubleBuffer buffer = new DoubleBuffer(10);
for (int i = 0; i < 100; i++) {
buffer.setNext(i);
}
assertTrue(buffer.isFull());
buffer.reset();
assertFalse(buffer.isFull());
assertEquals(0.0, buffer.getAverage());
double[] averageAndVariance = buffer.getAverageAndVariance();
assertEquals(0.0, averageAndVariance[0]);
assertEquals(0.0, averageAndVariance[1]);
}
/**
* Tests that if a lot of items are inserted the smoothing and looping works.
*/
public void testLoop() {
DoubleBuffer buffer = new DoubleBuffer(10);
for (int i = 0; i < 1000; i++) {
buffer.setNext(i);
assertEquals(i >= 9, buffer.isFull());
if (i > 10) {
assertEquals(i - 4.5, buffer.getAverage());
}
}
}
}
@@ -0,0 +1,63 @@
/**
* Copyright 2009 Google Inc. All Rights Reserved.
*/
package com.google.android.apps.mytracks.stats;
import junit.framework.TestCase;
import java.util.Random;
/**
* This class test the ExtremityMonitor class.
*
* @author Sandor Dornbush
*/
public class ExtremityMonitorTest extends TestCase {
public ExtremityMonitorTest(String name) {
super(name);
}
public void testInitialize() {
ExtremityMonitor monitor = new ExtremityMonitor();
assertEquals(Double.POSITIVE_INFINITY, monitor.getMin());
assertEquals(Double.NEGATIVE_INFINITY, monitor.getMax());
}
public void testSimple() {
ExtremityMonitor monitor = new ExtremityMonitor();
assertTrue(monitor.update(0));
assertTrue(monitor.update(1));
assertEquals(0.0, monitor.getMin());
assertEquals(1.0, monitor.getMax());
assertFalse(monitor.update(1));
assertFalse(monitor.update(0.5));
}
/**
* Throws a bunch of random numbers between [0,1] at the monitor.
*/
public void testRandom() {
ExtremityMonitor monitor = new ExtremityMonitor();
Random random = new Random(42);
for (int i = 0; i < 1000; i++) {
monitor.update(random.nextDouble());
}
assertTrue(monitor.getMin() < 0.1);
assertTrue(monitor.getMax() < 1.0);
assertTrue(monitor.getMin() >= 0.0);
assertTrue(monitor.getMax() > 0.9);
}
public void testReset() {
ExtremityMonitor monitor = new ExtremityMonitor();
assertTrue(monitor.update(0));
assertTrue(monitor.update(1));
monitor.reset();
assertEquals(Double.POSITIVE_INFINITY, monitor.getMin());
assertEquals(Double.NEGATIVE_INFINITY, monitor.getMax());
assertTrue(monitor.update(0));
assertTrue(monitor.update(1));
assertEquals(0.0, monitor.getMin());
assertEquals(1.0, monitor.getMax());
}
}
@@ -0,0 +1,105 @@
/*
* Copyright 2010 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 com.google.android.apps.mytracks.stats;
import junit.framework.TestCase;
/**
* Tests for {@link TripStatistics}.
* This only tests non-trivial pieces of that class.
*
* @author Rodrigo Damazio
*/
public class TripStatisticsTest extends TestCase {
private TripStatistics statistics;
@Override
protected void setUp() throws Exception {
super.setUp();
statistics = new TripStatistics();
}
public void testSetBounds() {
// This is not a trivial setter, conversion happens in it
statistics.setBounds(12345, -34567, 56789, -98765);
assertEquals(12345, statistics.getLeft());
assertEquals(-34567, statistics.getTop());
assertEquals(56789, statistics.getRight());
assertEquals(-98765, statistics.getBottom());
}
public void testMerge() {
TripStatistics statistics2 = new TripStatistics();
statistics.setStartTime(1000L); // Resulting start time
statistics.setStopTime(2500L);
statistics2.setStartTime(3000L);
statistics2.setStopTime(4000L); // Resulting stop time
statistics.setTotalTime(1500L);
statistics2.setTotalTime(1000L); // Result: 1500+1000
statistics.setMovingTime(700L);
statistics2.setMovingTime(600L); // Result: 700+600
statistics.setTotalDistance(750.0);
statistics2.setTotalDistance(350.0); // Result: 750+350
statistics.setTotalElevationGain(50.0);
statistics2.setTotalElevationGain(850.0); // Result: 850+50
statistics.setMaxSpeed(60.0); // Resulting max speed
statistics2.setMaxSpeed(30.0);
statistics.setMaxElevation(1250.0);
statistics.setMinElevation(1200.0); // Resulting min elevation
statistics2.setMaxElevation(3575.0); // Resulting max elevation
statistics2.setMinElevation(2800.0);
statistics.setMaxGrade(15.0);
statistics.setMinGrade(-25.0); // Resulting min grade
statistics2.setMaxGrade(35.0); // Resulting max grade
statistics2.setMinGrade(0.0);
// Resulting bounds: -10000, 35000, 30000, -40000
statistics.setBounds(-10000, 20000, 30000, -40000);
statistics2.setBounds(-5000, 35000, 0, 20000);
statistics.merge(statistics2);
assertEquals(1000L, statistics.getStartTime());
assertEquals(4000L, statistics.getStopTime());
assertEquals(2500L, statistics.getTotalTime());
assertEquals(1300L, statistics.getMovingTime());
assertEquals(1100.0, statistics.getTotalDistance());
assertEquals(900.0, statistics.getTotalElevationGain());
assertEquals(60.0, statistics.getMaxSpeed());
assertEquals(-10000, statistics.getLeft());
assertEquals(30000, statistics.getRight());
assertEquals(35000, statistics.getTop());
assertEquals(-40000, statistics.getBottom());
assertEquals(1200.0, statistics.getMinElevation());
assertEquals(3575.0, statistics.getMaxElevation());
assertEquals(-25.0, statistics.getMinGrade());
assertEquals(35.0, statistics.getMaxGrade());
}
public void testGetAverageSpeed() {
statistics.setTotalDistance(1000.0);
statistics.setTotalTime(50000); // in milliseconds
assertEquals(20.0, statistics.getAverageSpeed());
}
public void testGetAverageMovingSpeed() {
statistics.setTotalDistance(1000.0);
statistics.setMovingTime(20000); // in milliseconds
assertEquals(50.0, statistics.getAverageMovingSpeed());
}
}
@@ -0,0 +1,346 @@
// Copyright 2009 Google Inc. All Rights Reserved.
package com.google.android.apps.mytracks.stats;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import android.location.Location;
import junit.framework.TestCase;
/**
* Tests {@link TripStatisticsUpdater}.
*
* @author Sandor Dornbush
*/
public class TripStatisticsUpdaterTest extends TestCase {
private static final long ONE_SECOND = 1000;
private static final long TEN_SECONDS = 10 * ONE_SECOND;
private static final float MOVING_SPEED = 11.1f;
private TripStatisticsUpdater tripStatisticsUpdater = null;
@Override
protected void setUp() throws Exception {
tripStatisticsUpdater = new TripStatisticsUpdater(System.currentTimeMillis());
}
/**
* Sends some moving and waiting locations and then checks the statistics.
*/
public void testAddLocationSimple() {
long startTime = 1000;
tripStatisticsUpdater = new TripStatisticsUpdater(startTime);
TripStatistics tripStatistics = tripStatisticsUpdater.getTripStatistics();
assertEquals(0.0, tripStatisticsUpdater.getSmoothedElevation());
assertEquals(Double.POSITIVE_INFINITY, tripStatistics.getMinElevation());
assertEquals(Double.NEGATIVE_INFINITY, tripStatistics.getMaxElevation());
assertEquals(0.0, tripStatistics.getMaxSpeed());
assertEquals(Double.POSITIVE_INFINITY, tripStatistics.getMinGrade());
assertEquals(Double.NEGATIVE_INFINITY, tripStatistics.getMaxGrade());
assertEquals(0.0, tripStatistics.getTotalElevationGain());
assertEquals(0, tripStatistics.getMovingTime());
assertEquals(0.0, tripStatistics.getTotalDistance());
// Time:0 ~ 99; Location:0 ~ 99
addMoveLocations(100, startTime, tripStatistics, 0, 0);
// Time:100 ~ 199; Location:99
addWaitLocations(100, startTime, tripStatistics, 100, 99);
// Time:200 ~ 299; Location:100 ~ 199
addMoveLocations(100, startTime, tripStatistics, 200, 100);
// Time:300 ~ 399; Location:199
addWaitLocations(100, startTime, tripStatistics, 300, 199);
// Time:400 ~ 499; Location:200 ~ 299
addMoveLocations(100, startTime, tripStatistics, 400, 200);
// Time:500 ~ 599; Location:299
addWaitLocations(100, startTime, tripStatistics, 500, 299);
// Time:600 ~ 699; Location:300 ~ 399
addMoveLocations(100, startTime, tripStatistics, 600, 300);
}
/**
* Sends some disordered locations and checks the statistics. In some
* situation, especially when signal is not good, MyTracks may receive such
* data.
*/
public void testAddLocation_disorderedLocatiions() {
long startTime = 1000;
tripStatisticsUpdater = new TripStatisticsUpdater(startTime);
TripStatistics tripStatistics = tripStatisticsUpdater.getTripStatistics();
addLocations(5, startTime, tripStatistics, 0, 0);
addLocations(5, startTime, tripStatistics, 5, 0);
addLocations(5, startTime, tripStatistics, 10, -5);
addLocations(5, startTime, tripStatistics, 15, 5);
}
/**
* Tests {@link TripStatisticsUpdater#updateElevation(double)} with constant
* elevations.
*/
public void testElevationSimple() throws Exception {
for (double elevation = 0; elevation < 1000; elevation += 10) {
tripStatisticsUpdater = new TripStatisticsUpdater(System.currentTimeMillis());
for (int i = 0; i < 100; i++) {
assertEquals(0.0, tripStatisticsUpdater.updateElevation(elevation));
assertEquals(elevation, tripStatisticsUpdater.getSmoothedElevation());
TripStatistics tripStatistics = tripStatisticsUpdater.getTripStatistics();
assertEquals(elevation, tripStatistics.getMinElevation());
assertEquals(elevation, tripStatistics.getMaxElevation());
assertEquals(0.0, tripStatistics.getTotalElevationGain());
}
}
}
/**
* Tests {@link TripStatisticsUpdater#updateGrade(double, double)} with
* elevation gain.
*/
public void testElevationGain() throws Exception {
for (double i = 0; i < 1000; i++) {
double expectedGain;
if (i < TripStatisticsUpdater.ELEVATION_SMOOTHING_FACTOR - 1) {
expectedGain = 0;
} else if (i < TripStatisticsUpdater.ELEVATION_SMOOTHING_FACTOR) {
expectedGain = 0.5;
} else {
expectedGain = 1.0;
}
assertEquals(expectedGain, tripStatisticsUpdater.updateElevation(i));
assertEquals(i, tripStatisticsUpdater.getSmoothedElevation(),
TripStatisticsUpdater.ELEVATION_SMOOTHING_FACTOR / 2);
TripStatistics data = tripStatisticsUpdater.getTripStatistics();
assertEquals(0.0, data.getMinElevation());
assertEquals(i, data.getMaxElevation(), TripStatisticsUpdater.ELEVATION_SMOOTHING_FACTOR / 2);
assertEquals(
i, data.getTotalElevationGain(), TripStatisticsUpdater.ELEVATION_SMOOTHING_FACTOR);
}
}
/**
* Tests {@link TripStatisticsUpdater#updateGrade(double, double)} with grade
* of 1 and -1.
*/
public void testGradeSimple() throws Exception {
for (double i = 0; i < 1000; i++) {
/*
* The value of the elevation does not matter. This is just to fill the
* elevation buffer.
*/
tripStatisticsUpdater.updateElevation(i);
tripStatisticsUpdater.updateGrade(100, 100);
if (i >= TripStatisticsUpdater.GRADE_SMOOTHING_FACTOR
&& i >= TripStatisticsUpdater.ELEVATION_SMOOTHING_FACTOR) {
assertEquals(1.0, tripStatisticsUpdater.getTripStatistics().getMaxGrade());
assertEquals(1.0, tripStatisticsUpdater.getTripStatistics().getMinGrade());
}
}
for (double i = 0; i < 1000; i++) {
/*
* The value of the elevation does not matter. This is just to fill the
* elevation buffer.
*/
tripStatisticsUpdater.updateElevation(i);
tripStatisticsUpdater.updateGrade(100, -100);
if (i >= TripStatisticsUpdater.GRADE_SMOOTHING_FACTOR
&& i >= TripStatisticsUpdater.ELEVATION_SMOOTHING_FACTOR) {
assertEquals(1.0, tripStatisticsUpdater.getTripStatistics().getMaxGrade());
assertEquals(-1.0, tripStatisticsUpdater.getTripStatistics().getMinGrade());
}
}
}
/**
* Tests {@link TripStatisticsUpdater#updateGrade(double, double)} with
* distance of 1. The grade should get ignored.
*/
public void testGradeIgnoreShort() throws Exception {
for (double i = 0; i < 100; i++) {
/*
* The value of the elevation does not matter. This is just to fill the
* elevation buffer.
*/
tripStatisticsUpdater.updateElevation(i);
tripStatisticsUpdater.updateGrade(1, 100);
assertEquals(
Double.NEGATIVE_INFINITY, tripStatisticsUpdater.getTripStatistics().getMaxGrade());
assertEquals(
Double.POSITIVE_INFINITY, tripStatisticsUpdater.getTripStatistics().getMinGrade());
}
}
/**
* Tests {@link TripStatisticsUpdater#updateSpeed(long, double, long, double)}
* with speed of zero.
*/
public void testUpdateSpeedIncludeZero() {
for (int i = 0; i < 1000; i++) {
tripStatisticsUpdater.updateSpeed(i + ONE_SECOND, 0.0, i, 4.0);
assertEquals(0.0, tripStatisticsUpdater.getTripStatistics().getMaxSpeed());
}
}
/**
* Tests {@link TripStatisticsUpdater#updateSpeed(long, double, long, double)}
* with the error code 128. The speed should get ignored.
*/
public void testUpdateSpeedIngoreErrorCode() {
long time = 12344000;
tripStatisticsUpdater.updateSpeed(time + ONE_SECOND, 128.0, time, 0.0);
assertEquals(0.0, tripStatisticsUpdater.getTripStatistics().getMaxSpeed());
}
/**
* Tests {@link TripStatisticsUpdater#updateSpeed(long, double, long, double)}
* with a large speed change. The speed should get ignored.
*/
public void testUpdateSpeedIngoreLargeAcceleration() {
long time = 12344000;
tripStatisticsUpdater.updateSpeed(time + ONE_SECOND, 100.0, time, 1.0);
assertEquals(0.0, tripStatisticsUpdater.getTripStatistics().getMaxSpeed());
}
/**
* Tests {@link TripStatisticsUpdater#updateSpeed(long, double, long, double)}
* with constant speed.
*/
public void testUpdateSpeed() {
double speed = 4.0;
for (int i = 0; i < 1000; i++) {
tripStatisticsUpdater.updateSpeed(i + ONE_SECOND, speed, i, speed);
if (i >= TripStatisticsUpdater.SPEED_SMOOTHING_FACTOR) {
assertEquals(speed, tripStatisticsUpdater.getTripStatistics().getMaxSpeed());
}
}
}
/**
* Sends some locations which keeping moving and checks the statistics.
*
* @param points number of locations
* @param startTime start time of this track
* @param tripStatistics the TripStatistics object
* @param timeOffset offset to start time
* @param locationOffset location offset to start
*/
private void addMoveLocations(int points, long startTime, TripStatistics tripStatistics,
int timeOffset, int locationOffset) {
for (int i = 0; i < points; i++) {
// Going up by 1 meter each time.
// Moving by .001 degree latitude (111 meters).
// Each time slice is 10 seconds.
Location location = getLocation(i + locationOffset, (i + locationOffset) * .001, MOVING_SPEED,
startTime + (timeOffset + i) * TEN_SECONDS);
tripStatisticsUpdater.addLocation(location, PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT);
tripStatistics = tripStatisticsUpdater.getTripStatistics();
assertEquals((timeOffset + i) * TEN_SECONDS, tripStatistics.getTotalTime());
assertEquals((locationOffset + i) * TEN_SECONDS, tripStatistics.getMovingTime());
assertEquals(i + locationOffset, tripStatisticsUpdater.getSmoothedElevation(),
TripStatisticsUpdater.ELEVATION_SMOOTHING_FACTOR / 2);
assertEquals(0.0, tripStatistics.getMinElevation());
assertEquals(i + locationOffset, tripStatistics.getMaxElevation(),
TripStatisticsUpdater.ELEVATION_SMOOTHING_FACTOR / 2);
assertEquals(i + locationOffset, tripStatistics.getTotalElevationGain(),
TripStatisticsUpdater.ELEVATION_SMOOTHING_FACTOR);
if (i + locationOffset >= TripStatisticsUpdater.SPEED_SMOOTHING_FACTOR) {
assertEquals(MOVING_SPEED, tripStatistics.getMaxSpeed(), 0.1);
}
// If there are only moving locations in the track.
if (locationOffset == 0
&& (i + locationOffset) >= TripStatisticsUpdater.DISTANCE_SMOOTHING_FACTOR
&& (i + locationOffset) >= TripStatisticsUpdater.ELEVATION_SMOOTHING_FACTOR) {
// 1 m / 111 m = .009
assertEquals(0.009, tripStatistics.getMinGrade(), 0.0001);
assertEquals(0.009, tripStatistics.getMaxGrade(), 0.0001);
}
assertEquals((i + locationOffset) * 111.0, tripStatistics.getTotalDistance(),
(i + locationOffset) * 111.0 * 0.01);
}
}
/**
* Sends some locations which are not moving and checks the statistics.
*
* @param points number of locations
* @param startTime start time of this track
* @param tripStatistics the TripStatistics object
* @param timeOffset offset to start time
* @param locationOffset location offset to start
*/
private void addWaitLocations(int points, long startTime, TripStatistics tripStatistics,
int timeOffset, int locationOffset) {
for (int i = 0; i < points; i++) {
Location location = getLocation(
locationOffset, locationOffset * .001, 0, startTime + (i + timeOffset) * TEN_SECONDS);
tripStatisticsUpdater.addLocation(location, PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT);
tripStatistics = tripStatisticsUpdater.getTripStatistics();
assertEquals((i + timeOffset) * TEN_SECONDS, tripStatistics.getTotalTime());
assertEquals((locationOffset) * TEN_SECONDS, tripStatistics.getMovingTime());
assertEquals(locationOffset, tripStatisticsUpdater.getSmoothedElevation(),
TripStatisticsUpdater.ELEVATION_SMOOTHING_FACTOR / 2);
assertEquals(0.0, tripStatistics.getMinElevation());
assertEquals(locationOffset, tripStatistics.getMaxElevation(),
TripStatisticsUpdater.ELEVATION_SMOOTHING_FACTOR / 2);
assertEquals(locationOffset, tripStatistics.getTotalElevationGain(),
TripStatisticsUpdater.ELEVATION_SMOOTHING_FACTOR);
if (locationOffset >= TripStatisticsUpdater.SPEED_SMOOTHING_FACTOR) {
assertEquals(MOVING_SPEED, tripStatistics.getMaxSpeed(), 0.1);
}
assertEquals(MOVING_SPEED, tripStatistics.getMaxSpeed(), 0.1);
assertEquals(
locationOffset * 111.0, tripStatistics.getTotalDistance(), locationOffset * 111.0 * 0.01);
}
}
/**
* Sends some locations which are moving and checks some simple policy.
*
* @param points number of locations
* @param startTime start time of this track
* @param tripStatistics the TripStatistics object
* @param timeOffset offset to start time
* @param locationOffset location offset to start
*/
private void addLocations(int points, long startTime, TripStatistics tripStatistics,
int timeOffset, int locationOffset) {
for (int i = 0; i < points; i++) {
// 99999 means a speed should bigger than given speed.
Location location = getLocation(i + locationOffset, (i + locationOffset) * .001, 99999,
startTime + (timeOffset + i) * TEN_SECONDS);
tripStatisticsUpdater.addLocation(location, PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT);
tripStatistics = tripStatisticsUpdater.getTripStatistics();
assertTrue(tripStatistics.getMovingTime() <= tripStatistics.getTotalTime());
assertTrue(tripStatistics.getAverageSpeed() <= tripStatistics.getAverageMovingSpeed());
assertTrue(tripStatistics.getAverageMovingSpeed() <= tripStatistics.getMaxSpeed());
assertTrue(tripStatistics.getStopTime() >= tripStatistics.getStartTime());
}
}
/**
* Creates a location and returns it.
*
* @param altitude altitude of location
* @param latitude latitude of location
* @param speed speed of location
* @param time time of location
*/
private Location getLocation(double altitude, double latitude, float speed, long time) {
Location location = new Location("test");
location.setAccuracy(1.0f);
location.setLongitude(45.0);
location.setAltitude(altitude);
location.setLatitude(latitude);
location.setSpeed(speed);
location.setTime(time);
return location;
}
}
@@ -0,0 +1,38 @@
// Copyright 2010 Google Inc. All Rights Reserved.
package com.google.android.apps.mytracks.testing;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.Factory;
import android.content.Context;
/**
* A fake factory for {@link MyTracksProviderUtils} which always returns a
* predefined instance.
*
* @author Rodrigo Damazio
*/
public class TestingProviderUtilsFactory extends Factory {
private MyTracksProviderUtils instance;
public TestingProviderUtilsFactory(MyTracksProviderUtils instance) {
this.instance = instance;
}
@Override
protected MyTracksProviderUtils newForContext(Context context) {
return instance;
}
public static Factory installWithInstance(MyTracksProviderUtils instance) {
Factory oldFactory = Factory.getInstance();
Factory factory = new TestingProviderUtilsFactory(instance);
MyTracksProviderUtils.Factory.overrideInstance(factory);
return oldFactory;
}
public static void restoreOldFactory(Factory factory) {
MyTracksProviderUtils.Factory.overrideInstance(factory);
}
}
@@ -0,0 +1,75 @@
/*
* Copyright 2009 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 com.google.android.apps.mytracks.util;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.stats.TripStatistics;
import java.util.Vector;
import junit.framework.TestCase;
/**
* Tests for the Chart URL generator.
*
* @author Sandor Dornbush
*/
public class ChartURLGeneratorTest extends TestCase {
public void testgetChartUrl() {
Vector<Double> distances = new Vector<Double>();
Vector<Double> elevations = new Vector<Double>();
Track t = new Track();
TripStatistics stats = t.getTripStatistics();
stats.setMinElevation(0);
stats.setMaxElevation(2000);
stats.setTotalDistance(100);
distances.add(0.0);
elevations.add(10.0);
distances.add(10.0);
elevations.add(300.0);
distances.add(20.0);
elevations.add(800.0);
distances.add(50.0);
elevations.add(1900.0);
distances.add(75.0);
elevations.add(1200.0);
distances.add(90.0);
elevations.add(700.0);
distances.add(100.0);
elevations.add(70.0);
String chart = ChartURLGenerator.getChartUrl(distances,
elevations,
t,
"Title",
true);
assertEquals(
"http://chart.apis.google.com/chart?&chs=600x350&cht=lxy&"
+ "chtt=Title&chxt=x,y&chxr=0,0,0,0|1,0.0,2100.0,300&chco=009A00&"
+ "chm=B,00AA00,0,0,0&chg=100000,14.285714285714286,1,0&"
+ "chd=e:AAGZMzf.v.5l..,ATJJYY55kkVVCI",
chart);
}
}
@@ -0,0 +1,47 @@
/*
* Copyright 2010 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 com.google.android.apps.mytracks.util;
import junit.framework.TestCase;
/**
* A unit test for {@link ChartsExtendedEncoder}.
*
* @author Bartlomiej Niechwiej
*/
public class ChartsExtendedEncoderTest extends TestCase {
public void testGetEncodedValue_validArguments() {
// Valid arguments.
assertEquals("AK", ChartsExtendedEncoder.getEncodedValue(10));
assertEquals("JO", ChartsExtendedEncoder.getEncodedValue(590));
assertEquals("AA", ChartsExtendedEncoder.getEncodedValue(0));
// 64^2 = 4096.
assertEquals("..", ChartsExtendedEncoder.getEncodedValue(4095));
}
public void testGetEncodedValue_invalidArguments() {
// Invalid arguments.
assertEquals("__", ChartsExtendedEncoder.getEncodedValue(4096));
assertEquals("__", ChartsExtendedEncoder.getEncodedValue(1234564096));
assertEquals("__", ChartsExtendedEncoder.getEncodedValue(-10));
assertEquals("__", ChartsExtendedEncoder.getEncodedValue(-12324435));
}
public void testGetSeparator() {
assertEquals(",", ChartsExtendedEncoder.getSeparator());
}
}
@@ -0,0 +1,121 @@
/*
* Copyright 2010 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 com.google.android.apps.mytracks.util;
import android.os.Environment;
import java.io.File;
import junit.framework.TestCase;
/**
* Tests for {@link FileUtils}.
*
* @author Rodrigo Damazio
*/
public class FileUtilsTest extends TestCase {
/**
* Tests {@link FileUtils#buildExternalDirectoryPath(String...)}.
*/
public void testBuildExternalDirectoryPath() {
String expectedName = Environment.getExternalStorageDirectory() + File.separator
+ FileUtils.SDCARD_TOP_DIR + File.separator + "a" + File.separator + "b" + File.separator
+ "c";
String dirName = FileUtils.buildExternalDirectoryPath("a", "b", "c");
assertEquals(expectedName, dirName);
}
/**
* Tests {@link FileUtils#buildUniqueFileName(File, String, String)} when the
* file is new.
*/
public void testBuildUniqueFileName_new() {
String filename = FileUtils.buildUniqueFileName(new File("/dir"), "Filename", "ext");
assertEquals("Filename.ext", filename);
}
/**
* Tests {@link FileUtils#buildUniqueFileName(File, String, String)} when the
* file exists already.
*/
public void testBuildUniqueFileName_exist() {
// Expect "/default.prop" to exist on the phone/emulator
String filename = FileUtils.buildUniqueFileName(new File("/"), "default", "prop");
assertEquals("default(1).prop", filename);
}
/**
* Tests {@link FileUtils#sanitizeFileName(String)} with special characters.
* Verifies that they are sanitized.
*/
public void testSanitizeFileName() {
String name = "Swim\10ming-^across:/the/ pacific (ocean).";
String expected = "Swim_ming-^across_the_ pacific (ocean)_";
assertEquals(expected, FileUtils.sanitizeFileName(name));
}
/**
* Tests {@link FileUtils#sanitizeFileName(String)} with i18n characters (in
* Chinese and Russian). Verifies that they are allowed.
*/
public void testSanitizeFileName_i18n() {
String name = "您好-привет";
String expected = "您好-привет";
assertEquals(expected, FileUtils.sanitizeFileName(name));
}
/**
* Tests {@link FileUtils#sanitizeFileName(String)} with special FAT32
* characters. Verifies that they are allowed.
*/
public void testSanitizeFileName_special_characters() {
String name = "$%'-_@~`!(){}^#&+,;=[] ";
String expected = "$%'-_@~`!(){}^#&+,;=[] ";
assertEquals(expected, FileUtils.sanitizeFileName(name));
}
/**
* Tests {@link FileUtils#sanitizeFileName(String)} with multiple escaped
* characters in a row. Verifies that they are collapsed into one underscore.
*/
public void testSanitizeFileName_collapse() {
String name = "hello//there";
String expected = "hello_there";
assertEquals(expected, FileUtils.sanitizeFileName(name));
}
/**
* Tests {@link FileUtils#truncateFileName(File, String, String)}. Verifies
* the a long file name is truncated.
*/
public void testTruncateFileName() {
File directory = new File("/dir1/dir2/");
String suffix = ".gpx";
char[] name = new char[FileUtils.MAX_FAT32_PATH_LENGTH];
for (int i = 0; i < name.length; i++) {
name[i] = 'a';
}
String nameString = new String(name);
String truncated = FileUtils.truncateFileName(directory, nameString, suffix);
for (int i = 0; i < truncated.length(); i++) {
assertEquals('a', truncated.charAt(i));
}
assertEquals(FileUtils.MAX_FAT32_PATH_LENGTH,
new File(directory, truncated + suffix).getPath().length());
}
}
@@ -0,0 +1,183 @@
/*
* Copyright 2010 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 com.google.android.apps.mytracks.util;
import android.test.AndroidTestCase;
import java.util.GregorianCalendar;
import java.util.TimeZone;
/**
* Tests for {@link StringUtils}.
*
* @author Rodrigo Damazio
*/
public class StringUtilsTest extends AndroidTestCase {
/**
* Tests {@link StringUtils#formatDateTimeIso8601(long)}.
*/
public void testFormatDateTimeIso8601() {
assertEquals("1970-01-01T00:00:12.345Z", StringUtils.formatDateTimeIso8601(12345));
}
/**
* Tests {@link StringUtils#formatElapsedTime(long)}.
*/
public void testformatElapsedTime() {
// 1 second
assertEquals("00:01", StringUtils.formatElapsedTime(1000));
// 10 seconds
assertEquals("00:10", StringUtils.formatElapsedTime(10000));
// 1 minute
assertEquals("01:00", StringUtils.formatElapsedTime(60000));
// 10 minutes
assertEquals("10:00", StringUtils.formatElapsedTime(600000));
// 1 hour
assertEquals("1:00:00", StringUtils.formatElapsedTime(3600000));
// 10 hours
assertEquals("10:00:00", StringUtils.formatElapsedTime(36000000));
// 100 hours
assertEquals("100:00:00", StringUtils.formatElapsedTime(360000000));
}
/**
* Tests {@link StringUtils#formatElapsedTimeWithHour(long)}.
*/
public void testformatElapsedTimeWithHour() {
// 1 second
assertEquals("0:00:01", StringUtils.formatElapsedTimeWithHour(1000));
// 10 seconds
assertEquals("0:00:10", StringUtils.formatElapsedTimeWithHour(10000));
// 1 minute
assertEquals("0:01:00", StringUtils.formatElapsedTimeWithHour(60000));
// 10 minutes
assertEquals("0:10:00", StringUtils.formatElapsedTimeWithHour(600000));
// 1 hour
assertEquals("1:00:00", StringUtils.formatElapsedTimeWithHour(3600000));
// 10 hours
assertEquals("10:00:00", StringUtils.formatElapsedTimeWithHour(36000000));
// 100 hours
assertEquals("100:00:00", StringUtils.formatElapsedTimeWithHour(360000000));
}
/**
* Tests {@link StringUtils#formatDistance(android.content.Context, double,
* boolean)}.
*/
public void testFormatDistance() {
// A large number in metric
assertEquals("5.00 km", StringUtils.formatDistance(getContext(), 5000, true));
// A large number in imperial
assertEquals("3.11 mi", StringUtils.formatDistance(getContext(), 5000, false));
// A small number in metric
assertEquals("100.00 m", StringUtils.formatDistance(getContext(), 100, true));
// A small number in imperial
assertEquals("328.08 ft", StringUtils.formatDistance(getContext(), 100, false));
}
/**
* Tests {@link StringUtils#formatCData(String)}.
*/
public void testFormatCData() {
assertEquals("<![CDATA[hello]]>", StringUtils.formatCData("hello"));
assertEquals("<![CDATA[hello]]]]><![CDATA[>there]]>", StringUtils.formatCData("hello]]>there"));
}
/**
* Tests {@link StringUtils#getTime(String)}.
*/
public void testGetTime() {
assertGetTime("2010-05-04T03:02:01", 2010, 5, 4, 3, 2, 1, 0);
assertGetTime("2010-05-04T03:02:01Z", 2010, 5, 4, 3, 2, 1, 0);
}
/**
* Tests {@link StringUtils#getTime(String)} with fractional seconds.
*/
public void testGetTime_fractional() {
assertGetTime("2010-05-04T03:02:01.3", 2010, 5, 4, 3, 2, 1, 300);
assertGetTime("2010-05-04T03:02:01.35", 2010, 5, 4, 3, 2, 1, 350);
assertGetTime("2010-05-04T03:02:01.352Z", 2010, 5, 4, 3, 2, 1, 352);
assertGetTime("2010-05-04T03:02:01.3525Z", 2010, 5, 4, 3, 2, 1, 352);
}
/**
* Tests {@link StringUtils#getTime(String)} with time zone.
*/
public void testGetTime_timezone() {
assertGetTime("2010-05-04T03:02:01Z", 2010, 5, 4, 3, 2, 1, 0);
assertGetTime("2010-05-04T03:02:01+00:00", 2010, 5, 4, 3, 2, 1, 0);
assertGetTime("2010-05-04T03:02:01-00:00", 2010, 5, 4, 3, 2, 1, 0);
assertGetTime("2010-05-04T03:02:01+01:00", 2010, 5, 4, 2, 2, 1, 0);
assertGetTime("2010-05-04T03:02:01+10:30", 2010, 5, 3, 16, 32, 1, 0);
assertGetTime("2010-05-04T03:02:01-09:30", 2010, 5, 4, 12, 32, 1, 0);
assertGetTime("2010-05-04T03:02:01-05:00", 2010, 5, 4, 8, 2, 1, 0);
}
/**
* Tests {@link StringUtils#getTime(String)} with fractional seconds and time
* zone.
*/
public void testGetTime_fractionalAndTimezone() {
assertGetTime("2010-05-04T03:02:01.352Z", 2010, 5, 4, 3, 2, 1, 352);
assertGetTime("2010-05-04T03:02:01.47+00:00", 2010, 5, 4, 3, 2, 1, 470);
assertGetTime("2010-05-04T03:02:01.5791+03:00", 2010, 5, 4, 0, 2, 1, 579);
assertGetTime("2010-05-04T03:02:01.8-05:30", 2010, 5, 4, 8, 32, 1, 800);
}
/**
* Asserts the {@link StringUtils#getTime(String)} returns the expected
* values.
*
* @param xmlDateTime the xml date time string
* @param year the expected year
* @param month the expected month
* @param day the expected day
* @param hour the expected hour
* @param minute the expected minute
* @param second the expected second
* @param millisecond the expected milliseconds
*/
private void assertGetTime(String xmlDateTime, int year, int month, int day, int hour, int minute,
int second, int millisecond) {
GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
calendar.set(year, month - 1, day, hour, minute, second);
calendar.set(GregorianCalendar.MILLISECOND, millisecond);
assertEquals(calendar.getTimeInMillis(), StringUtils.getTime(xmlDateTime));
}
/**
* Tests {@link StringUtils#getTimeParts(long)} with a positive number.
*/
public void testGetTimeParts_postive() {
int parts[] = StringUtils.getTimeParts(61000);
assertEquals(1, parts[0]);
assertEquals(1, parts[1]);
assertEquals(0, parts[2]);
}
/**
* Tests {@link StringUtils#getTimeParts(long)} with a negative number.
*/
public void testGetTimeParts_negative() {
int parts[] = StringUtils.getTimeParts(-61000);
assertEquals(-1, parts[0]);
assertEquals(-1, parts[1]);
assertEquals(0, parts[2]);
}
}
@@ -0,0 +1,71 @@
/*
* Copyright 2010 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 com.google.android.apps.mytracks.util;
import com.google.android.maps.mytracks.R;
import android.test.AndroidTestCase;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
/**
* Tests {@link TrackNameUtils}.
*
* @author Matthew Simmons
*/
public class TrackNameUtilsTest extends AndroidTestCase {
private static final long TRACK_ID = 1L;
private static final long START_TIME = 1288213406000L;
/**
* Tests when the track_name_key is
* settings_recording_track_name_date_local_value.
*/
public void testTrackName_date_local() {
PreferencesUtils.setString(getContext(), R.string.track_name_key,
getContext().getString(R.string.settings_recording_track_name_date_local_value));
assertEquals(StringUtils.formatDateTime(getContext(), START_TIME),
TrackNameUtils.getTrackName(getContext(), TRACK_ID, START_TIME, null));
}
/**
* Tests when the track_name_key is
* settings_recording_track_name_date_iso_8601_value.
*/
public void testTrackName_date_iso_8601() {
PreferencesUtils.setString(getContext(), R.string.track_name_key,
getContext().getString(R.string.settings_recording_track_name_date_iso_8601_value));
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(
TrackNameUtils.ISO_8601_FORMAT, Locale.US);
assertEquals(simpleDateFormat.format(new Date(START_TIME)),
TrackNameUtils.getTrackName(getContext(), TRACK_ID, START_TIME, null));
}
/**
* Tests when the track_name_key is
* settings_recording_track_name_number_value.
*/
public void testTrackName_number() {
PreferencesUtils.setString(getContext(), R.string.track_name_key,
getContext().getString(R.string.settings_recording_track_name_number_value));
assertEquals(
"Track " + TRACK_ID, TrackNameUtils.getTrackName(getContext(), TRACK_ID, START_TIME, null));
}
}