tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 198098e9253e65e98ecf5c16f34d0aa29b0a01c7
parent 3ff7b558d46a55785907ae7d093cd58d65cfa975
Author: mcarare <48995920+mcarare@users.noreply.github.com>
Date:   Mon, 15 Dec 2025 08:47:18 +0000

Bug 2005228 - Refactor Address middlewares to use injected dispatchers. r=android-reviewers,giorga

Differential Revision: https://phabricator.services.mozilla.com/D276176

Diffstat:
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/address/store/AddressMiddleware.kt | 8+++++---
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/address/store/AddressStructureMiddleware.kt | 11+++++------
Mmobile/android/fenix/app/src/test/java/org/mozilla/fenix/settings/address/store/AddressStoreTest.kt | 39+++++++++++++++++++++++++--------------
3 files changed, 35 insertions(+), 23 deletions(-)

diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/address/store/AddressMiddleware.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/address/store/AddressMiddleware.kt @@ -8,8 +8,8 @@ import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers.IO -import kotlinx.coroutines.MainScope import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import mozilla.components.lib.state.Middleware import mozilla.components.lib.state.MiddlewareContext import org.mozilla.fenix.GleanMetrics.Addresses @@ -19,11 +19,13 @@ import org.mozilla.fenix.GleanMetrics.Addresses * * @param environment used to hold the dependencies. * @param scope a [CoroutineScope] used to launch coroutines. + * @param mainDispatcher the dispatcher to run UI-related code on. * @param ioDispatcher the dispatcher to run background code on. */ class AddressMiddleware( private val environment: AddressEnvironment, - private val scope: CoroutineScope = MainScope(), + private val scope: CoroutineScope, + private val mainDispatcher: CoroutineDispatcher = Dispatchers.Main, private val ioDispatcher: CoroutineDispatcher = IO, ) : Middleware<AddressState, AddressAction> { override fun invoke( @@ -56,7 +58,7 @@ class AddressMiddleware( private fun runAndNavigateBack(action: suspend () -> Unit) = scope.launch(ioDispatcher) { action() - scope.launch(Dispatchers.Main) { + withContext(mainDispatcher) { environment.navigateBack() } } diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/address/store/AddressStructureMiddleware.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/address/store/AddressStructureMiddleware.kt @@ -6,8 +6,7 @@ package org.mozilla.fenix.settings.address.store import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers.IO -import kotlinx.coroutines.MainScope +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import mozilla.components.concept.engine.autofill.AddressStructure import mozilla.components.lib.state.Middleware @@ -45,8 +44,8 @@ data class UnknownLocalizationKey( */ class AddressStructureMiddleware( private val environment: AddressEnvironment, - private val scope: CoroutineScope = MainScope(), - private val ioDispatcher: CoroutineDispatcher = IO, + private val scope: CoroutineScope, + private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO, ) : Middleware<AddressState, AddressAction> { override fun invoke( context: MiddlewareContext<AddressState, AddressAction>, @@ -69,7 +68,7 @@ class AddressStructureMiddleware( store: Store<AddressState, AddressAction>, initialLoad: Boolean, ) = scope.launch(ioDispatcher) { - val structure = environment?.getAddressStructure(store.state.address.country) ?: return@launch + val structure = environment.getAddressStructure(store.state.address.country) structure.validate(store.state.address.country) store.dispatch( AddressStructureLoaded( @@ -89,7 +88,7 @@ class AddressStructureMiddleware( } if (localizationKey is AddressStructure.Field.LocalizationKey.Unknown) { - environment?.submitCaughtException( + environment.submitCaughtException( UnknownLocalizationKey(countryCode, localizationKey.value), ) } diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/settings/address/store/AddressStoreTest.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/settings/address/store/AddressStoreTest.kt @@ -2,24 +2,23 @@ package org.mozilla.fenix.settings.address.store import androidx.test.ext.junit.runners.AndroidJUnit4 import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.runTest import mozilla.components.concept.engine.autofill.AddressStructure import mozilla.components.concept.storage.Address import mozilla.components.concept.storage.UpdatableAddressFields -import mozilla.components.support.test.rule.MainCoroutineRule -import mozilla.components.support.test.rule.runTestOnMain import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue -import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class AddressStoreTest { - @get:Rule - val coroutinesTestRule = MainCoroutineRule() + + private val testDispatcher = StandardTestDispatcher() @Test - fun `GIVEN a store WHEN a user edits an address THEN the address structure is loaded`() = runTestOnMain { + fun `GIVEN a store WHEN a user edits an address THEN the address structure is loaded`() = runTest(testDispatcher) { val expectedAddressStructure = AddressStructure( listOf( AddressStructure.Field.TextField(AddressStructure.Field.ID.Name, AddressStructure.Field.LocalizationKey.Name), @@ -35,6 +34,7 @@ class AddressStoreTest { } store.dispatch(ViewAppeared) + testDispatcher.scheduler.advanceUntilIdle() assertEquals( AddressStructureState.Loaded(expectedAddressStructure), @@ -43,7 +43,7 @@ class AddressStoreTest { } @Test - fun `GIVEN a store WHEN a user edits an address and changes the country THEN the address structure is loaded`() = runTestOnMain { + fun `GIVEN a store WHEN a user edits an address and changes the country THEN the address structure is loaded`() = runTest(testDispatcher) { val expectedAddressStructure = AddressStructure( listOf( AddressStructure.Field.TextField(AddressStructure.Field.ID.Name, AddressStructure.Field.LocalizationKey.Name), @@ -82,7 +82,10 @@ class AddressStoreTest { assertEquals("WA", store.state.address.addressLevel1) store.dispatch(ViewAppeared) + testDispatcher.scheduler.advanceUntilIdle() + store.dispatch(FormChange.Country("CA")) + testDispatcher.scheduler.advanceUntilIdle() assertEquals("CA", store.state.address.country) assertEquals("AL", store.state.address.addressLevel1) @@ -94,7 +97,7 @@ class AddressStoreTest { } @Test - fun `GIVEN a store WHEN an address structure is loaded with an Unknown LocalizationKey THEN submit an exception`() = runTestOnMain { + fun `GIVEN a store WHEN an address structure is loaded with an Unknown LocalizationKey THEN submit an exception`() = runTest(testDispatcher) { val expectedAddressStructure = AddressStructure( listOf( AddressStructure.Field.TextField(AddressStructure.Field.ID.Name, AddressStructure.Field.LocalizationKey.Name), @@ -112,6 +115,7 @@ class AddressStoreTest { } store.dispatch(ViewAppeared) + testDispatcher.scheduler.advanceUntilIdle() assertEquals( UnknownLocalizationKey("US", "unknown-key"), @@ -120,7 +124,7 @@ class AddressStoreTest { } @Test - fun `GIVEN a store WHEN a user updates the address THEN the address is updated`() = runTestOnMain { + fun `GIVEN a store WHEN a user updates the address THEN the address is updated`() = runTest(testDispatcher) { val store = makeStore(this) { copy( getAddressStructure = { _ -> @@ -155,6 +159,7 @@ class AddressStoreTest { FormChange.Tel("555-555-5555"), FormChange.Email("mo@zilla.com"), ).forEach(store::dispatch) + testDispatcher.scheduler.advanceUntilIdle() val expected = UpdatableAddressFields( name = "Work", @@ -172,7 +177,7 @@ class AddressStoreTest { } @Test - fun `GIVEN a state with no guid WHEN a user taps save THEN create and navigateBack is called on the environment`() = runTestOnMain { + fun `GIVEN a state with no guid WHEN a user taps save THEN create and navigateBack is called on the environment`() = runTest(testDispatcher) { var navigateBackCalled = false var createdAddress: UpdatableAddressFields? = null @@ -188,6 +193,7 @@ class AddressStoreTest { store.dispatch(FormChange.Name("Work")) store.dispatch(SaveTapped) + testDispatcher.scheduler.advanceUntilIdle() val expected = emptyUpdatableAddress.copy(name = "Work") @@ -196,7 +202,7 @@ class AddressStoreTest { } @Test - fun `GIVEN a state with an existing address WHEN a user taps save THEN update and navigateBack is called on the environment`() = runTestOnMain { + fun `GIVEN a state with an existing address WHEN a user taps save THEN update and navigateBack is called on the environment`() = runTest(testDispatcher) { var navigateBackCalled = false var updatedAddress: Pair<String, UpdatableAddressFields>? = null @@ -211,6 +217,7 @@ class AddressStoreTest { store.dispatch(FormChange.Name("Home")) store.dispatch(SaveTapped) + testDispatcher.scheduler.advanceUntilIdle() val expected = Pair("BEEF", emptyUpdatableAddress.copy(name = "Home", organization = "Mozilla")) @@ -219,7 +226,7 @@ class AddressStoreTest { } @Test - fun `GIVEN a state with an existing address WHEN a user taps save THEN delete and navigateBack is called on the environment`() = runTestOnMain { + fun `GIVEN a state with an existing address WHEN a user taps save THEN delete and navigateBack is called on the environment`() = runTest(testDispatcher) { var navigateBackCalled = false var deletedGuid: String? = null @@ -233,10 +240,14 @@ class AddressStoreTest { } assertEquals(DialogState.Inert, store.state.deleteDialog) + store.dispatch(DeleteTapped) + testDispatcher.scheduler.advanceUntilIdle() assertEquals(DialogState.Presenting, store.state.deleteDialog) + store.dispatch(DeleteDialogAction.DeleteTapped) + testDispatcher.scheduler.advanceUntilIdle() val expected = "BEEF" @@ -254,8 +265,8 @@ class AddressStoreTest { return AddressStore( state, listOf( - AddressMiddleware(environment, scope, coroutinesTestRule.testDispatcher), - AddressStructureMiddleware(environment, scope, coroutinesTestRule.testDispatcher), + AddressMiddleware(environment, scope, testDispatcher, testDispatcher), + AddressStructureMiddleware(environment, scope, testDispatcher), ), ) }