Updating location tracker tests

This commit is contained in:
Maxime NATUREL 2022-06-27 16:13:02 +02:00
parent 3b09323ee4
commit 0488ce822f
3 changed files with 40 additions and 41 deletions

View file

@ -61,7 +61,6 @@ class LocationTracker @Inject constructor(
@VisibleForTesting @VisibleForTesting
var hasLocationFromGPSProvider = false var hasLocationFromGPSProvider = false
// TODO update unit tests
private val _locations = MutableSharedFlow<Location>(replay = 1) private val _locations = MutableSharedFlow<Location>(replay = 1)
/** /**

View file

@ -19,21 +19,21 @@ package im.vector.app.features.location
import android.content.Context import android.content.Context
import android.location.Location import android.location.Location
import android.location.LocationManager import android.location.LocationManager
import im.vector.app.core.utils.Debouncer import im.vector.app.features.session.coroutineScope
import im.vector.app.core.utils.createBackgroundHandler import im.vector.app.test.fakes.FakeActiveSessionHolder
import im.vector.app.test.fakes.FakeContext import im.vector.app.test.fakes.FakeContext
import im.vector.app.test.fakes.FakeHandler
import im.vector.app.test.fakes.FakeLocationManager import im.vector.app.test.fakes.FakeLocationManager
import im.vector.app.test.test
import io.mockk.every import io.mockk.every
import io.mockk.just import io.mockk.just
import io.mockk.mockk import io.mockk.mockk
import io.mockk.mockkConstructor
import io.mockk.mockkStatic import io.mockk.mockkStatic
import io.mockk.runs import io.mockk.runs
import io.mockk.slot
import io.mockk.unmockkAll import io.mockk.unmockkAll
import io.mockk.verify import io.mockk.verify
import io.mockk.verifyOrder import io.mockk.verifyOrder
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runTest
import org.amshove.kluent.shouldBeEqualTo import org.amshove.kluent.shouldBeEqualTo
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
@ -45,26 +45,18 @@ private const val AN_ACCURACY = 5.0f
class LocationTrackerTest { class LocationTrackerTest {
private val fakeHandler = FakeHandler()
private val fakeLocationManager = FakeLocationManager() private val fakeLocationManager = FakeLocationManager()
private val fakeContext = FakeContext().also { private val fakeContext = FakeContext().also {
it.givenService(Context.LOCATION_SERVICE, android.location.LocationManager::class.java, fakeLocationManager.instance) it.givenService(Context.LOCATION_SERVICE, android.location.LocationManager::class.java, fakeLocationManager.instance)
} }
private val fakeActiveSessionHolder = FakeActiveSessionHolder()
private lateinit var locationTracker: LocationTracker private lateinit var locationTracker: LocationTracker
@Before @Before
fun setUp() { fun setUp() {
mockkConstructor(Debouncer::class) mockkStatic("im.vector.app.features.session.SessionCoroutineScopesKt")
every { anyConstructed<Debouncer>().cancelAll() } just runs locationTracker = LocationTracker(fakeContext.instance, fakeActiveSessionHolder.instance)
val runnable = slot<Runnable>()
every { anyConstructed<Debouncer>().debounce(any(), MIN_TIME_TO_UPDATE_LOCATION_MILLIS, capture(runnable)) } answers {
runnable.captured.run()
true
}
mockkStatic("im.vector.app.core.utils.HandlerKt")
every { createBackgroundHandler(any()) } returns fakeHandler.instance
locationTracker = LocationTracker(fakeContext.instance)
fakeLocationManager.givenRemoveUpdates(locationTracker) fakeLocationManager.givenRemoveUpdates(locationTracker)
} }
@ -139,13 +131,11 @@ class LocationTrackerTest {
} }
@Test @Test
fun `when location updates are received from fused provider then fused locations are taken in priority`() { fun `when location updates are received from fused provider then fused locations are taken in priority`() = runTest {
every { fakeActiveSessionHolder.fakeSession.coroutineScope } returns this
val providers = listOf(LocationManager.GPS_PROVIDER, LocationManager.FUSED_PROVIDER, LocationManager.NETWORK_PROVIDER) val providers = listOf(LocationManager.GPS_PROVIDER, LocationManager.FUSED_PROVIDER, LocationManager.NETWORK_PROVIDER)
mockAvailableProviders(providers) mockAvailableProviders(providers)
val callback = mockCallback()
locationTracker.addCallback(callback)
locationTracker.start() locationTracker.start()
val fusedLocation = mockLocation( val fusedLocation = mockLocation(
provider = LocationManager.FUSED_PROVIDER, provider = LocationManager.FUSED_PROVIDER,
latitude = 1.0, latitude = 1.0,
@ -159,29 +149,31 @@ class LocationTrackerTest {
val networkLocation = mockLocation( val networkLocation = mockLocation(
provider = LocationManager.NETWORK_PROVIDER provider = LocationManager.NETWORK_PROVIDER
) )
val resultUpdates = locationTracker.locations.test(this)
locationTracker.onLocationChanged(fusedLocation) locationTracker.onLocationChanged(fusedLocation)
locationTracker.onLocationChanged(gpsLocation) locationTracker.onLocationChanged(gpsLocation)
locationTracker.onLocationChanged(networkLocation) locationTracker.onLocationChanged(networkLocation)
advanceTimeBy(MIN_TIME_TO_UPDATE_LOCATION_MILLIS + 1)
val expectedLocationData = LocationData( val expectedLocationData = LocationData(
latitude = 1.0, latitude = 1.0,
longitude = 3.0, longitude = 3.0,
uncertainty = 4.0 uncertainty = 4.0
) )
verify { callback.onLocationUpdate(expectedLocationData) } resultUpdates
verify { anyConstructed<Debouncer>().debounce(any(), MIN_TIME_TO_UPDATE_LOCATION_MILLIS, any()) } .assertValues(listOf(expectedLocationData))
.finish()
locationTracker.hasLocationFromFusedProvider shouldBeEqualTo true locationTracker.hasLocationFromFusedProvider shouldBeEqualTo true
locationTracker.hasLocationFromGPSProvider shouldBeEqualTo false locationTracker.hasLocationFromGPSProvider shouldBeEqualTo false
} }
@Test @Test
fun `when location updates are received from gps provider then gps locations are taken if none are received from fused provider`() { fun `when location updates are received from gps provider then gps locations are taken if none are received from fused provider`() = runTest {
every { fakeActiveSessionHolder.fakeSession.coroutineScope } returns this
val providers = listOf(LocationManager.GPS_PROVIDER, LocationManager.FUSED_PROVIDER, LocationManager.NETWORK_PROVIDER) val providers = listOf(LocationManager.GPS_PROVIDER, LocationManager.FUSED_PROVIDER, LocationManager.NETWORK_PROVIDER)
mockAvailableProviders(providers) mockAvailableProviders(providers)
val callback = mockCallback()
locationTracker.addCallback(callback)
locationTracker.start() locationTracker.start()
val gpsLocation = mockLocation( val gpsLocation = mockLocation(
provider = LocationManager.GPS_PROVIDER, provider = LocationManager.GPS_PROVIDER,
latitude = 1.0, latitude = 1.0,
@ -192,66 +184,75 @@ class LocationTrackerTest {
val networkLocation = mockLocation( val networkLocation = mockLocation(
provider = LocationManager.NETWORK_PROVIDER provider = LocationManager.NETWORK_PROVIDER
) )
val resultUpdates = locationTracker.locations.test(this)
locationTracker.onLocationChanged(gpsLocation) locationTracker.onLocationChanged(gpsLocation)
locationTracker.onLocationChanged(networkLocation) locationTracker.onLocationChanged(networkLocation)
advanceTimeBy(MIN_TIME_TO_UPDATE_LOCATION_MILLIS + 1)
val expectedLocationData = LocationData( val expectedLocationData = LocationData(
latitude = 1.0, latitude = 1.0,
longitude = 3.0, longitude = 3.0,
uncertainty = 4.0 uncertainty = 4.0
) )
verify { callback.onLocationUpdate(expectedLocationData) } resultUpdates
verify { anyConstructed<Debouncer>().debounce(any(), MIN_TIME_TO_UPDATE_LOCATION_MILLIS, any()) } .assertValues(listOf(expectedLocationData))
.finish()
locationTracker.hasLocationFromFusedProvider shouldBeEqualTo false locationTracker.hasLocationFromFusedProvider shouldBeEqualTo false
locationTracker.hasLocationFromGPSProvider shouldBeEqualTo true locationTracker.hasLocationFromGPSProvider shouldBeEqualTo true
} }
@Test @Test
fun `when location updates are received from network provider then network locations are taken if none are received from fused or gps provider`() { fun `when location updates are received from network provider then network locations are taken if none are received from fused or gps provider`() = runTest {
every { fakeActiveSessionHolder.fakeSession.coroutineScope } returns this
val providers = listOf(LocationManager.GPS_PROVIDER, LocationManager.FUSED_PROVIDER, LocationManager.NETWORK_PROVIDER) val providers = listOf(LocationManager.GPS_PROVIDER, LocationManager.FUSED_PROVIDER, LocationManager.NETWORK_PROVIDER)
mockAvailableProviders(providers) mockAvailableProviders(providers)
val callback = mockCallback()
locationTracker.addCallback(callback)
locationTracker.start() locationTracker.start()
val networkLocation = mockLocation( val networkLocation = mockLocation(
provider = LocationManager.NETWORK_PROVIDER, provider = LocationManager.NETWORK_PROVIDER,
latitude = 1.0, latitude = 1.0,
longitude = 3.0, longitude = 3.0,
accuracy = 4f accuracy = 4f
) )
val resultUpdates = locationTracker.locations.test(this)
locationTracker.onLocationChanged(networkLocation) locationTracker.onLocationChanged(networkLocation)
advanceTimeBy(MIN_TIME_TO_UPDATE_LOCATION_MILLIS + 1)
val expectedLocationData = LocationData( val expectedLocationData = LocationData(
latitude = 1.0, latitude = 1.0,
longitude = 3.0, longitude = 3.0,
uncertainty = 4.0 uncertainty = 4.0
) )
verify { callback.onLocationUpdate(expectedLocationData) } resultUpdates
verify { anyConstructed<Debouncer>().debounce(any(), MIN_TIME_TO_UPDATE_LOCATION_MILLIS, any()) } .assertValues(listOf(expectedLocationData))
.finish()
locationTracker.hasLocationFromFusedProvider shouldBeEqualTo false locationTracker.hasLocationFromFusedProvider shouldBeEqualTo false
locationTracker.hasLocationFromGPSProvider shouldBeEqualTo false locationTracker.hasLocationFromGPSProvider shouldBeEqualTo false
} }
@Test @Test
fun `when requesting the last location then last location is notified via callback`() { fun `when requesting the last location then last location is notified via location updates flow`() = runTest {
every { fakeActiveSessionHolder.fakeSession.coroutineScope } returns this
val providers = listOf(LocationManager.GPS_PROVIDER) val providers = listOf(LocationManager.GPS_PROVIDER)
fakeLocationManager.givenActiveProviders(providers) fakeLocationManager.givenActiveProviders(providers)
val lastLocation = mockLocation(provider = LocationManager.GPS_PROVIDER) val lastLocation = mockLocation(provider = LocationManager.GPS_PROVIDER)
fakeLocationManager.givenLastLocationForProvider(provider = LocationManager.GPS_PROVIDER, location = lastLocation) fakeLocationManager.givenLastLocationForProvider(provider = LocationManager.GPS_PROVIDER, location = lastLocation)
fakeLocationManager.givenRequestUpdatesForProvider(provider = LocationManager.GPS_PROVIDER, listener = locationTracker) fakeLocationManager.givenRequestUpdatesForProvider(provider = LocationManager.GPS_PROVIDER, listener = locationTracker)
val callback = mockCallback()
locationTracker.addCallback(callback)
locationTracker.start() locationTracker.start()
val resultUpdates = locationTracker.locations.test(this)
locationTracker.requestLastKnownLocation() locationTracker.requestLastKnownLocation()
advanceTimeBy(MIN_TIME_TO_UPDATE_LOCATION_MILLIS + 1)
val expectedLocationData = LocationData( val expectedLocationData = LocationData(
latitude = A_LATITUDE, latitude = A_LATITUDE,
longitude = A_LONGITUDE, longitude = A_LONGITUDE,
uncertainty = AN_ACCURACY.toDouble() uncertainty = AN_ACCURACY.toDouble()
) )
verify { callback.onLocationUpdate(expectedLocationData) } resultUpdates
.assertValues(listOf(expectedLocationData))
.finish()
} }
@Test @Test
@ -259,7 +260,6 @@ class LocationTrackerTest {
locationTracker.stop() locationTracker.stop()
verify { fakeLocationManager.instance.removeUpdates(locationTracker) } verify { fakeLocationManager.instance.removeUpdates(locationTracker) }
verify { anyConstructed<Debouncer>().cancelAll() }
locationTracker.callbacks.isEmpty() shouldBeEqualTo true locationTracker.callbacks.isEmpty() shouldBeEqualTo true
locationTracker.hasLocationFromGPSProvider shouldBeEqualTo false locationTracker.hasLocationFromGPSProvider shouldBeEqualTo false
locationTracker.hasLocationFromFusedProvider shouldBeEqualTo false locationTracker.hasLocationFromFusedProvider shouldBeEqualTo false
@ -276,7 +276,6 @@ class LocationTrackerTest {
private fun mockCallback(): LocationTracker.Callback { private fun mockCallback(): LocationTracker.Callback {
return mockk<LocationTracker.Callback>().also { return mockk<LocationTracker.Callback>().also {
every { it.onNoLocationProviderAvailable() } just runs every { it.onNoLocationProviderAvailable() } just runs
every { it.onLocationUpdate(any()) } just runs
} }
} }

View file

@ -27,6 +27,7 @@ class FakeActiveSessionHolder(
) { ) {
val instance = mockk<ActiveSessionHolder> { val instance = mockk<ActiveSessionHolder> {
every { getActiveSession() } returns fakeSession every { getActiveSession() } returns fakeSession
every { getSafeActiveSession() } returns fakeSession
} }
fun expectSetsActiveSession(session: Session) { fun expectSetsActiveSession(session: Session) {