diff --git a/MyTracks/src/com/google/android/apps/mytracks/content/TrackDataHub.java b/MyTracks/src/com/google/android/apps/mytracks/content/TrackDataHub.java index ffef9527c..7749ad42f 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/content/TrackDataHub.java +++ b/MyTracks/src/com/google/android/apps/mytracks/content/TrackDataHub.java @@ -219,6 +219,8 @@ public class TrackDataHub { listenerHandlerThread = new HandlerThread("trackDataContentThread"); listenerHandlerThread.start(); listenerHandler = new Handler(listenerHandlerThread.getLooper()); + + resetState(); } /** @@ -416,13 +418,6 @@ public class TrackDataHub { public void unregisterTrackDataListener(TrackDataListener listener) { synchronized (listeners) { listeners.unregisterTrackDataListener(listener); - - if (!listeners.hasListeners()) { - // We lost our last listener, don't bother keeping the listener state. - // If any of the old listeners happens to be re-added, we'll use state from its - // old registration instead. - resetState(); - } // Don't load any data or start internal listeners if start() hasn't been // called. When it is called, we'll do both things. @@ -931,9 +926,7 @@ public class TrackDataHub { // a few of them (why miss the oportunity?). Log.i(TAG, "Resampling point set after " + numLoadedPoints + " points."); - firstSeenLocationId = -1; - lastSeenLocationId = -1; - numLoadedPoints = 0; + resetState(); synchronized (listeners) { sampledListeners = getListenersFor(ListenerDataType.POINT_UPDATES); sampledOutListeners = getListenersFor(ListenerDataType.SAMPLED_OUT_POINT_UPDATES); @@ -990,6 +983,9 @@ public class TrackDataHub { if (pointSamplingFrequency == -1) { // Now we already have at least one point, calculate the sampling // frequency. + // It should be noted that a non-obvious consequence of this sampling is that + // no matter how many points we get in the newest batch, we'll never exceed + // MAX_DISPLAYED_TRACK_POINTS = 2 * TARGET_DISPLAYED_TRACK_POINTS before resampling. long numTotalPoints = lastStoredLocationId - localFirstSeenLocationId; pointSamplingFrequency = (int) (1 + numTotalPoints / Constants.TARGET_DISPLAYED_TRACK_POINTS); diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/content/TrackDataHubTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/content/TrackDataHubTest.java index 81e3401a2..12a72999e 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/content/TrackDataHubTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/content/TrackDataHubTest.java @@ -24,14 +24,8 @@ import static com.google.android.testing.mocking.AndroidMock.leq; import static com.google.android.testing.mocking.AndroidMock.same; import com.google.android.apps.mytracks.Constants; -import com.google.android.apps.mytracks.content.MyTracksProviderUtils; -import com.google.android.apps.mytracks.content.Track; -import com.google.android.apps.mytracks.content.TrackDataHub; -import com.google.android.apps.mytracks.content.TrackDataListener; -import com.google.android.apps.mytracks.content.DataSourcesWrapper; -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.content.MyTracksProviderUtils.LocationFactory; +import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator; import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType; import com.google.android.apps.mytracks.content.TrackDataListener.ProviderState; import com.google.android.apps.mytracks.services.TrackRecordingServiceTest.MockContext; @@ -55,6 +49,8 @@ import android.test.mock.MockContentResolver; import java.lang.reflect.Constructor; import java.util.EnumSet; +import java.util.HashSet; +import java.util.Set; import org.easymock.Capture; import org.easymock.IAnswer; @@ -66,7 +62,7 @@ import org.easymock.IAnswer; */ public class TrackDataHubTest extends AndroidTestCase { - private static final long TRACK_ID = 42; + private static final long TRACK_ID = 42L; private MyTracksProviderUtils providerUtils; private TrackDataHub hub; private TrackDataListeners listeners; @@ -106,8 +102,8 @@ public class TrackDataHubTest extends AndroidTestCase { } }; - listener1 = AndroidMock.createMock("listener1", TrackDataListener.class); - listener2 = AndroidMock.createMock("listener2", TrackDataListener.class); + listener1 = AndroidMock.createStrictMock("listener1", TrackDataListener.class); + listener2 = AndroidMock.createStrictMock("listener2", TrackDataListener.class); } @Override @@ -146,49 +142,48 @@ public class TrackDataHubTest extends AndroidTestCase { listener1.onTrackUpdated(track); listener2.onTrackUpdated(track); - AndroidMock.replay(dataSources, providerUtils, listener1, listener2); + replay(); hub.registerTrackDataListener(listener1, EnumSet.of(ListenerDataType.TRACK_UPDATES)); hub.start(); hub.registerTrackDataListener(listener2, EnumSet.of(ListenerDataType.TRACK_UPDATES)); - AndroidMock.verify(listener1, listener2, dataSources); - AndroidMock.reset(listener1, listener2, dataSources); + verifyAndReset(); ContentObserver observer = observerCapture.getValue(); + expect(providerUtils.getTrack(TRACK_ID)).andStubReturn(track); // Now expect an update. listener1.onTrackUpdated(track); listener2.onTrackUpdated(track); - AndroidMock.replay(listener1, listener2, dataSources); + replay(); observer.onChange(false); - AndroidMock.verify(listener1, listener2, dataSources); - AndroidMock.reset(listener1, listener2, dataSources); + verifyAndReset(); // Unregister one, get another update. + expect(providerUtils.getTrack(TRACK_ID)).andStubReturn(track); listener2.onTrackUpdated(track); - AndroidMock.replay(listener1, listener2, dataSources); + replay(); hub.unregisterTrackDataListener(listener1); observer.onChange(false); - AndroidMock.verify(listener1, listener2, dataSources); - AndroidMock.reset(listener1, listener2, dataSources); + verifyAndReset(); // Unregister the other, expect internal unregistration dataSources.unregisterContentObserver(observer); - AndroidMock.replay(listener1, listener2, dataSources); + replay(); hub.unregisterTrackDataListener(listener2); observer.onChange(false); - AndroidMock.verify(listener1, listener2, dataSources); + verifyAndReset(); } private static class FixedSizeCursorAnswer implements IAnswer { @@ -208,6 +203,90 @@ public class TrackDataHubTest extends AndroidTestCase { } } + private static class FixedSizeLocationIterator implements LocationIterator { + private final long startId; + private final Location[] locs; + private final Set splitIndexSet = new HashSet(); + private int currentIdx = -1; + + public FixedSizeLocationIterator(long startId, int size) { + this(startId, size, null); + } + + public FixedSizeLocationIterator(long startId, int size, int... splitIndices) { + this.startId = startId; + this.locs = new Location[size]; + + for (int i = 0; i < size; i++) { + Location loc = new Location("gps"); + loc.setLatitude(-15.0 + i / 1000.0); + loc.setLongitude(37 + i / 1000.0); + loc.setAltitude(i); + + locs[i] = loc; + } + + if (splitIndices != null) { + for (int splitIdx : splitIndices) { + splitIndexSet.add(splitIdx); + + Location splitLoc = locs[splitIdx]; + splitLoc.setLatitude(100.0); + splitLoc.setLongitude(200.0); + } + } + } + + public void expectLocationsDelivered(TrackDataListener listener) { + for (int i = 0; i < locs.length; i++) { + if (splitIndexSet.contains(i)) { + listener.onSegmentSplit(); + } else { + listener.onNewTrackPoint(locs[i]); + } + } + } + + public void expectSampledLocationsDelivered( + TrackDataListener listener, int sampleFrequency, boolean includeSampledOut) { + for (int i = 0; i < locs.length; i++) { + if (splitIndexSet.contains(i)) { + listener.onSegmentSplit(); + } else if (i % sampleFrequency == 0) { + listener.onNewTrackPoint(locs[i]); + } else if (includeSampledOut) { + listener.onSampledOutTrackPoint(locs[i]); + } + } + } + + @Override + public boolean hasNext() { + return currentIdx < (locs.length - 1); + } + + @Override + public Location next() { + currentIdx++; + return locs[currentIdx]; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + @Override + public long getLocationId() { + return startId + currentIdx; + } + + @Override + public void close() { + // Do nothing + } + } + public void testWaypointListen() { Capture observerCapture = new Capture(); prefs.edit().putLong("recordingTrack", TRACK_ID) @@ -249,14 +328,13 @@ public class TrackDataHubTest extends AndroidTestCase { listener2.onNewWaypoint(wpt2); listener2.onNewWaypointsDone(); - AndroidMock.replay(dataSources, providerUtils, listener1, listener2); + replay(); hub.registerTrackDataListener(listener1, EnumSet.of(ListenerDataType.WAYPOINT_UPDATES)); hub.start(); hub.registerTrackDataListener(listener2, EnumSet.of(ListenerDataType.WAYPOINT_UPDATES)); - AndroidMock.verify(listener1, listener2, dataSources, providerUtils); - AndroidMock.reset(listener1, listener2, dataSources, providerUtils); + verifyAndReset(); ContentObserver observer = observerCapture.getValue(); @@ -280,12 +358,11 @@ public class TrackDataHubTest extends AndroidTestCase { listener1.onNewWaypointsDone(); listener2.onNewWaypointsDone(); - AndroidMock.replay(listener1, listener2, dataSources, providerUtils); + replay(); observer.onChange(false); - AndroidMock.verify(listener1, listener2, dataSources, providerUtils); - AndroidMock.reset(listener1, listener2, dataSources, providerUtils); + verifyAndReset(); // Unregister one, get another update. expect(providerUtils.getWaypointsCursor( @@ -305,32 +382,335 @@ public class TrackDataHubTest extends AndroidTestCase { listener2.onNewWaypoint(wpt4); listener2.onNewWaypointsDone(); - AndroidMock.replay(listener1, listener2, dataSources, providerUtils); + replay(); hub.unregisterTrackDataListener(listener1); observer.onChange(false); - AndroidMock.verify(listener1, listener2, dataSources, providerUtils); - AndroidMock.reset(listener1, listener2, dataSources, providerUtils); + verifyAndReset(); // Unregister the other, expect internal unregistration dataSources.unregisterContentObserver(observer); - AndroidMock.replay(listener1, listener2, dataSources, providerUtils); + replay(); hub.unregisterTrackDataListener(listener2); observer.onChange(false); - AndroidMock.verify(listener1, listener2, dataSources, providerUtils); + verifyAndReset(); } public void testPointsListen() { - // TODO + Capture observerCapture = new Capture(); + prefs.edit().putLong("recordingTrack", TRACK_ID) + .putLong("selectedTrack", TRACK_ID).commit(); + + expectStart(); + dataSources.registerContentObserver( + eq(TrackPointsColumns.CONTENT_URI), eq(false), capture(observerCapture)); + + FixedSizeLocationIterator locationIterator = new FixedSizeLocationIterator(1, 10, 5); + expect(providerUtils.getLocationIterator( + eq(TRACK_ID), eq(0L), eq(false), isA(LocationFactory.class))) + .andReturn(locationIterator); + expect(providerUtils.getLastLocationId(TRACK_ID)).andReturn(10L); + + listener1.clearTrackPoints(); + locationIterator.expectLocationsDelivered(listener1); + listener1.onNewTrackPointsDone(); + + replay(); + + hub.start(); + hub.registerTrackDataListener(listener1, EnumSet.of(ListenerDataType.POINT_UPDATES)); + + verifyAndReset(); + + // Register a second listener - it will get the same points as the previous one + locationIterator = new FixedSizeLocationIterator(1, 10, 5); + expect(providerUtils.getLocationIterator( + eq(TRACK_ID), eq(0L), eq(false), isA(LocationFactory.class))) + .andReturn(locationIterator); + expect(providerUtils.getLastLocationId(TRACK_ID)).andReturn(10L); + + listener2.clearTrackPoints(); + locationIterator.expectLocationsDelivered(listener2); + listener2.onNewTrackPointsDone(); + + replay(); + + hub.start(); + hub.registerTrackDataListener(listener2, EnumSet.of(ListenerDataType.POINT_UPDATES)); + + verifyAndReset(); + + // Deliver more points - should go to both listeners, without clearing. + ContentObserver observer = observerCapture.getValue(); + + locationIterator = new FixedSizeLocationIterator(11, 10, 1); + expect(providerUtils.getLocationIterator( + eq(TRACK_ID), eq(11L), eq(false), isA(LocationFactory.class))) + .andReturn(locationIterator); + expect(providerUtils.getLastLocationId(TRACK_ID)).andReturn(20L); + + locationIterator.expectLocationsDelivered(listener1); + locationIterator.expectLocationsDelivered(listener2); + listener1.onNewTrackPointsDone(); + listener2.onNewTrackPointsDone(); + + replay(); + + observer.onChange(false); + + verifyAndReset(); + + // Unregister listener1, switch tracks to ensure data is cleared/reloaded. + locationIterator = new FixedSizeLocationIterator(101, 10); + expect(providerUtils.getLocationIterator( + eq(TRACK_ID + 1), eq(0L), eq(false), isA(LocationFactory.class))) + .andReturn(locationIterator); + expect(providerUtils.getLastLocationId(TRACK_ID + 1)).andReturn(110L); + + listener2.clearTrackPoints(); + locationIterator.expectLocationsDelivered(listener2); + listener2.onNewTrackPointsDone(); + + replay(); + + hub.unregisterTrackDataListener(listener1); + hub.loadTrack(TRACK_ID + 1); + + verifyAndReset(); } - public void testPointsListen_resample() { - // TODO + public void testPointsListen_beforeStart() { + + } + + public void testPointsListen_reRegister() { + Capture observerCapture = new Capture(); + prefs.edit().putLong("recordingTrack", TRACK_ID) + .putLong("selectedTrack", TRACK_ID).commit(); + + expectStart(); + dataSources.registerContentObserver( + eq(TrackPointsColumns.CONTENT_URI), eq(false), capture(observerCapture)); + + FixedSizeLocationIterator locationIterator = new FixedSizeLocationIterator(1, 10, 5); + expect(providerUtils.getLocationIterator( + eq(TRACK_ID), eq(0L), eq(false), isA(LocationFactory.class))) + .andReturn(locationIterator); + expect(providerUtils.getLastLocationId(TRACK_ID)).andReturn(10L); + + listener1.clearTrackPoints(); + locationIterator.expectLocationsDelivered(listener1); + listener1.onNewTrackPointsDone(); + + replay(); + + hub.start(); + hub.registerTrackDataListener(listener1, EnumSet.of(ListenerDataType.POINT_UPDATES)); + + verifyAndReset(); + + // Unregister + ContentObserver observer = observerCapture.getValue(); + dataSources.unregisterContentObserver(observer); + + replay(); + + hub.unregisterTrackDataListener(listener1); + + verifyAndReset(); + + // Register again, except only points since unregistered. + dataSources.registerContentObserver( + eq(TrackPointsColumns.CONTENT_URI), eq(false), capture(observerCapture)); + + locationIterator = new FixedSizeLocationIterator(11, 10); + expect(providerUtils.getLocationIterator( + eq(TRACK_ID), eq(11L), eq(false), isA(LocationFactory.class))) + .andReturn(locationIterator); + expect(providerUtils.getLastLocationId(TRACK_ID)).andReturn(20L); + + locationIterator.expectLocationsDelivered(listener1); + listener1.onNewTrackPointsDone(); + + replay(); + + hub.registerTrackDataListener(listener1, EnumSet.of(ListenerDataType.POINT_UPDATES)); + + verifyAndReset(); + + // Deliver more points - should still be incremental. + locationIterator = new FixedSizeLocationIterator(21, 10, 1); + expect(providerUtils.getLocationIterator( + eq(TRACK_ID), eq(21L), eq(false), isA(LocationFactory.class))) + .andReturn(locationIterator); + expect(providerUtils.getLastLocationId(TRACK_ID)).andReturn(30L); + + locationIterator.expectLocationsDelivered(listener1); + listener1.onNewTrackPointsDone(); + + replay(); + + observer.onChange(false); + + verifyAndReset(); + } + + public void testPointsListen_reRegisterTrackChanged() { + Capture observerCapture = new Capture(); + prefs.edit().putLong("recordingTrack", TRACK_ID) + .putLong("selectedTrack", TRACK_ID).commit(); + + expectStart(); + dataSources.registerContentObserver( + eq(TrackPointsColumns.CONTENT_URI), eq(false), capture(observerCapture)); + + FixedSizeLocationIterator locationIterator = new FixedSizeLocationIterator(1, 10, 5); + expect(providerUtils.getLocationIterator( + eq(TRACK_ID), eq(0L), eq(false), isA(LocationFactory.class))) + .andReturn(locationIterator); + expect(providerUtils.getLastLocationId(TRACK_ID)).andReturn(10L); + + listener1.clearTrackPoints(); + locationIterator.expectLocationsDelivered(listener1); + listener1.onNewTrackPointsDone(); + + replay(); + + hub.start(); + hub.registerTrackDataListener(listener1, EnumSet.of(ListenerDataType.POINT_UPDATES)); + + verifyAndReset(); + + // Unregister + ContentObserver observer = observerCapture.getValue(); + dataSources.unregisterContentObserver(observer); + + replay(); + + hub.unregisterTrackDataListener(listener1); + + verifyAndReset(); + + // Register again after track changed, expect all points. + dataSources.registerContentObserver( + eq(TrackPointsColumns.CONTENT_URI), eq(false), capture(observerCapture)); + + locationIterator = new FixedSizeLocationIterator(1, 10); + expect(providerUtils.getLocationIterator( + eq(TRACK_ID + 1), eq(0L), eq(false), isA(LocationFactory.class))) + .andReturn(locationIterator); + expect(providerUtils.getLastLocationId(TRACK_ID + 1)).andReturn(10L); + + listener1.clearTrackPoints(); + locationIterator.expectLocationsDelivered(listener1); + listener1.onNewTrackPointsDone(); + + replay(); + + hub.loadTrack(TRACK_ID + 1); + hub.registerTrackDataListener(listener1, EnumSet.of(ListenerDataType.POINT_UPDATES)); + + verifyAndReset(); + } + + public void testPointsListen_largeTrackSampling() { + Capture observerCapture = new Capture(); + prefs.edit().putLong("recordingTrack", TRACK_ID) + .putLong("selectedTrack", TRACK_ID).commit(); + + expectStart(); + dataSources.registerContentObserver( + eq(TrackPointsColumns.CONTENT_URI), eq(false), capture(observerCapture)); + + FixedSizeLocationIterator locationIterator = new FixedSizeLocationIterator(1, 20000, 4, 253, 700, 712); + expect(providerUtils.getLocationIterator( + eq(TRACK_ID), eq(0L), eq(false), isA(LocationFactory.class))) + .andReturn(locationIterator); + expect(providerUtils.getLastLocationId(TRACK_ID)).andReturn(20000L); + + listener1.clearTrackPoints(); + listener2.clearTrackPoints(); + locationIterator.expectSampledLocationsDelivered(listener1, 4, false); + locationIterator.expectSampledLocationsDelivered(listener2, 4, true); + listener1.onNewTrackPointsDone(); + listener2.onNewTrackPointsDone(); + + replay(); + + hub.registerTrackDataListener(listener1, + EnumSet.of(ListenerDataType.POINT_UPDATES)); + hub.registerTrackDataListener(listener2, + EnumSet.of(ListenerDataType.POINT_UPDATES, ListenerDataType.SAMPLED_OUT_POINT_UPDATES)); + hub.start(); + + verifyAndReset(); + } + + public void testPointsListen_resampling() { + Capture observerCapture = new Capture(); + prefs.edit().putLong("recordingTrack", TRACK_ID) + .putLong("selectedTrack", TRACK_ID).commit(); + + expectStart(); + dataSources.registerContentObserver( + eq(TrackPointsColumns.CONTENT_URI), eq(false), capture(observerCapture)); + + // Deliver 3000 points (no sampling happens) + FixedSizeLocationIterator locationIterator = new FixedSizeLocationIterator(1, 3000, 5); + expect(providerUtils.getLocationIterator( + eq(TRACK_ID), eq(0L), eq(false), isA(LocationFactory.class))) + .andReturn(locationIterator); + expect(providerUtils.getLastLocationId(TRACK_ID)).andReturn(3000L); + + listener1.clearTrackPoints(); + locationIterator.expectLocationsDelivered(listener1); + listener1.onNewTrackPointsDone(); + + replay(); + + hub.start(); + hub.registerTrackDataListener(listener1, EnumSet.of(ListenerDataType.POINT_UPDATES)); + + verifyAndReset(); + + // Now deliver 3000 more (incrementally sampled) + ContentObserver observer = observerCapture.getValue(); + locationIterator = new FixedSizeLocationIterator(3001, 3000); + expect(providerUtils.getLocationIterator( + eq(TRACK_ID), eq(3001L), eq(false), isA(LocationFactory.class))) + .andReturn(locationIterator); + expect(providerUtils.getLastLocationId(TRACK_ID)).andReturn(6000L); + + locationIterator.expectSampledLocationsDelivered(listener1, 2, false); + listener1.onNewTrackPointsDone(); + + replay(); + + observer.onChange(false); + + verifyAndReset(); + + // Now another 3000 (triggers resampling) + locationIterator = new FixedSizeLocationIterator(1, 9000); + expect(providerUtils.getLocationIterator( + eq(TRACK_ID), eq(0L), eq(false), isA(LocationFactory.class))) + .andReturn(locationIterator); + expect(providerUtils.getLastLocationId(TRACK_ID)).andReturn(9000L); + + listener1.clearTrackPoints(); + locationIterator.expectSampledLocationsDelivered(listener1, 2, false); + listener1.onNewTrackPointsDone(); + + replay(); + + observer.onChange(false); + + verifyAndReset(); } public void testLocationListen() { @@ -338,6 +718,8 @@ public class TrackDataHubTest extends AndroidTestCase { } public void testCompassListen() throws Exception { + AndroidMock.resetToDefault(listener1); + Sensor compass = newSensor(); expect(dataSources.getSensor(Sensor.TYPE_ORIENTATION)).andReturn(compass); Capture listenerCapture = new Capture(); @@ -359,7 +741,7 @@ public class TrackDataHubTest extends AndroidTestCase { listener1.onProviderStateChange(isA(ProviderState.class)); AndroidMock.expectLastCall().anyTimes(); - AndroidMock.replay(dataSources, providerUtils, listener1); + replay(); hub.registerTrackDataListener(listener1, EnumSet.of(ListenerDataType.COMPASS_UPDATES, ListenerDataType.LOCATION_UPDATES)); @@ -370,8 +752,7 @@ public class TrackDataHubTest extends AndroidTestCase { event.values[0] = 42.0f; sensorListener.onSensorChanged(event); - AndroidMock.verify(dataSources, providerUtils, listener1); - AndroidMock.reset(dataSources, providerUtils, listener1); + verifyAndReset(); // Expect the heading update to include declination. listener1.onCurrentHeadingChanged(52.0); @@ -382,7 +763,7 @@ public class TrackDataHubTest extends AndroidTestCase { listener1.onCurrentLocationChanged(isA(Location.class)); AndroidMock.expectLastCall().anyTimes(); - AndroidMock.replay(dataSources, providerUtils, listener1); + replay(); // Now try injecting a location update, triggering a declination update. Location location = new Location("gps"); @@ -393,19 +774,18 @@ public class TrackDataHubTest extends AndroidTestCase { locationListener.onLocationChanged(location); sensorListener.onSensorChanged(event); - AndroidMock.verify(dataSources, providerUtils, listener1); - AndroidMock.reset(dataSources, providerUtils, listener1); + verifyAndReset(); listener1.onCurrentHeadingChanged(52.0); - AndroidMock.replay(dataSources, providerUtils, listener1); + replay(); // Now try changing the known declination - it should still return the old declination, since // updates only happen sparsely. declination = 20.0f; sensorListener.onSensorChanged(event); - AndroidMock.verify(dataSources, providerUtils, listener1); + verifyAndReset(); } private Sensor newSensor() throws Exception { @@ -438,19 +818,18 @@ public class TrackDataHubTest extends AndroidTestCase { expect(listener1.onReportSpeedChanged(true)).andReturn(false); expect(listener2.onReportSpeedChanged(true)).andReturn(false); - AndroidMock.replay(dataSources, providerUtils, listener1, listener2); + replay(); hub.registerTrackDataListener(listener1, EnumSet.of(ListenerDataType.DISPLAY_PREFERENCES)); hub.start(); hub.registerTrackDataListener(listener2, EnumSet.of(ListenerDataType.DISPLAY_PREFERENCES)); - AndroidMock.verify(dataSources, providerUtils, listener1, listener2); - AndroidMock.reset(dataSources, providerUtils, listener1, listener2); + verifyAndReset(); expect(listener1.onReportSpeedChanged(false)).andReturn(false); expect(listener2.onReportSpeedChanged(false)).andReturn(false); - AndroidMock.replay(dataSources, providerUtils, listener1, listener2); + replay(); prefs.edit() .putBoolean(speedKey, false) @@ -464,29 +843,26 @@ public class TrackDataHubTest extends AndroidTestCase { expect(listener1.onUnitsChanged(false)).andReturn(false); expect(listener2.onUnitsChanged(false)).andReturn(false); - AndroidMock.replay(dataSources, providerUtils, listener1, listener2); + replay(); prefs.edit() .putBoolean(metricUnitsKey, false) .commit(); listener.onSharedPreferenceChanged(prefs, metricUnitsKey); - AndroidMock.verify(dataSources, providerUtils, listener1, listener2); - } - - public void testFullListener() { - // TODO: test loading a track, getting updates, loading another, unloading - } - - public void testRelisten() { - // TODO: test re-registering an old points listener - } - - public void testRelisten_changed() { - // TODO: test register, get points, unregister, change track, register + verifyAndReset(); } private void expectStart() { dataSources.registerOnSharedPreferenceChangeListener(capture(preferenceListenerCapture)); } + + private void replay() { + AndroidMock.replay(dataSources, providerUtils, listener1, listener2); + } + + private void verifyAndReset() { + AndroidMock.verify(listener1, listener2, dataSources, providerUtils); + AndroidMock.reset(listener1, listener2, dataSources, providerUtils); + } }