@@ -21,40 +21,41 @@ import com.x8bit.bitwarden.data.autofill.model.FilledData
21
21
import com.x8bit.bitwarden.data.autofill.parser.AutofillParser
22
22
import com.x8bit.bitwarden.data.autofill.util.createAutofillSavedItemIntentSender
23
23
import com.x8bit.bitwarden.data.autofill.util.toAutofillSaveItem
24
+ import com.x8bit.bitwarden.data.platform.base.FakeDispatcherManager
24
25
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
25
- import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
26
26
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
27
27
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
28
28
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
29
+ import io.mockk.clearMocks
29
30
import io.mockk.coEvery
30
31
import io.mockk.coVerify
31
32
import io.mockk.every
32
33
import io.mockk.just
33
34
import io.mockk.mockk
34
35
import io.mockk.mockkStatic
35
36
import io.mockk.runs
37
+ import io.mockk.slot
36
38
import io.mockk.unmockkStatic
37
39
import io.mockk.verify
38
- import kotlinx.coroutines.ExperimentalCoroutinesApi
39
- import kotlinx.coroutines.test.UnconfinedTestDispatcher
40
+ import kotlinx.coroutines.test.StandardTestDispatcher
40
41
import kotlinx.coroutines.test.runTest
41
42
import org.junit.jupiter.api.AfterEach
42
43
import org.junit.jupiter.api.BeforeEach
43
44
import org.junit.jupiter.api.Test
44
45
45
- @OptIn(ExperimentalCoroutinesApi ::class )
46
46
class AutofillProcessorTest {
47
47
private lateinit var autofillProcessor: AutofillProcessor
48
48
49
- private val dispatcherManager: DispatcherManager = mockk()
49
+ private val testDispatcher = StandardTestDispatcher ()
50
+ private val dispatcherManager: FakeDispatcherManager =
51
+ FakeDispatcherManager (unconfined = testDispatcher)
50
52
private val cancellationSignal: CancellationSignal = mockk()
51
53
private val filledDataBuilder: FilledDataBuilder = mockk()
52
54
private val fillResponseBuilder: FillResponseBuilder = mockk()
53
55
private val parser: AutofillParser = mockk()
54
56
private val policyManager: PolicyManager = mockk()
55
57
private val saveInfoBuilder: SaveInfoBuilder = mockk()
56
58
private val settingsRepository: SettingsRepository = mockk()
57
- private val testDispatcher = UnconfinedTestDispatcher ()
58
59
59
60
private val appInfo: AutofillAppInfo = AutofillAppInfo (
60
61
context = mockk(),
@@ -67,7 +68,6 @@ class AutofillProcessorTest {
67
68
fun setup () {
68
69
mockkStatic(::createAutofillSavedItemIntentSender)
69
70
mockkStatic(AutofillRequest .Fillable ::toAutofillSaveItem)
70
- every { dispatcherManager.unconfined } returns testDispatcher
71
71
72
72
autofillProcessor = AutofillProcessorImpl (
73
73
dispatcherManager = dispatcherManager,
@@ -82,9 +82,6 @@ class AutofillProcessorTest {
82
82
83
83
@AfterEach
84
84
fun teardown () {
85
- verify(exactly = 1 ) {
86
- dispatcherManager.unconfined
87
- }
88
85
unmockkStatic(::createAutofillSavedItemIntentSender)
89
86
unmockkStatic(AutofillRequest .Fillable ::toAutofillSaveItem)
90
87
}
@@ -179,6 +176,8 @@ class AutofillProcessorTest {
179
176
request = fillRequest,
180
177
)
181
178
179
+ testDispatcher.scheduler.runCurrent()
180
+
182
181
// Verify
183
182
coVerify(exactly = 1 ) {
184
183
filledDataBuilder.build(
@@ -386,6 +385,106 @@ class AutofillProcessorTest {
386
385
saveCallback.onSuccess()
387
386
}
388
387
}
388
+
389
+ @Suppress(" MaxLineLength" )
390
+ @Test
391
+ fun `processFillRequest should allow additional requests to be invoked after cancellation signal is triggered` () {
392
+ // Setup
393
+ val autofillPartition: AutofillPartition = mockk()
394
+ val autofillRequest: AutofillRequest .Fillable = mockk {
395
+ every { packageName } returns PACKAGE_NAME
396
+ every { partition } returns autofillPartition
397
+ }
398
+ val fillRequest: FillRequest = mockk()
399
+ val saveInfo: SaveInfo = mockk()
400
+ val filledData = FilledData (
401
+ filledPartitions = listOf (mockk()),
402
+ ignoreAutofillIds = emptyList(),
403
+ originalPartition = mockk(),
404
+ uri = null ,
405
+ vaultItemInlinePresentationSpec = null ,
406
+ isVaultLocked = false ,
407
+ )
408
+ val fillResponse: FillResponse = mockk()
409
+ val cancellationSignalListener = slot<CancellationSignal .OnCancelListener >()
410
+ every {
411
+ cancellationSignal.setOnCancelListener(capture(cancellationSignalListener))
412
+ } just runs
413
+ every {
414
+ parser.parse(autofillAppInfo = appInfo, fillRequest = fillRequest)
415
+ } returns autofillRequest
416
+ coEvery { filledDataBuilder.build(autofillRequest = autofillRequest) } returns filledData
417
+ every {
418
+ saveInfoBuilder.build(
419
+ autofillAppInfo = appInfo,
420
+ autofillPartition = autofillPartition,
421
+ fillRequest = fillRequest,
422
+ packageName = PACKAGE_NAME ,
423
+ )
424
+ } returns saveInfo
425
+ every {
426
+ fillResponseBuilder.build(
427
+ autofillAppInfo = appInfo,
428
+ filledData = filledData,
429
+ saveInfo = saveInfo,
430
+ )
431
+ } returns fillResponse
432
+ every { fillCallback.onSuccess(fillResponse) } just runs
433
+
434
+ // Test
435
+ autofillProcessor.processFillRequest(
436
+ autofillAppInfo = appInfo,
437
+ cancellationSignal = cancellationSignal,
438
+ fillCallback = fillCallback,
439
+ request = fillRequest,
440
+ )
441
+
442
+ // Cancel the job and validate that nothing runs
443
+ cancellationSignalListener.captured.onCancel()
444
+ testDispatcher.scheduler.runCurrent()
445
+ verify(exactly = 1 ) {
446
+ // These run as they are not part of the coroutine
447
+ cancellationSignal.setOnCancelListener(any())
448
+ parser.parse(autofillAppInfo = appInfo, fillRequest = fillRequest)
449
+ }
450
+ coVerify(exactly = 0 ) {
451
+ filledDataBuilder.build(autofillRequest = autofillRequest)
452
+ }
453
+ verify(exactly = 0 ) {
454
+ fillResponseBuilder.build(
455
+ autofillAppInfo = appInfo,
456
+ filledData = filledData,
457
+ saveInfo = saveInfo,
458
+ )
459
+ fillCallback.onSuccess(fillResponse)
460
+ }
461
+ clearMocks(cancellationSignal, parser, answers = false )
462
+
463
+ // Test again after cancelling
464
+ autofillProcessor.processFillRequest(
465
+ autofillAppInfo = appInfo,
466
+ cancellationSignal = cancellationSignal,
467
+ fillCallback = fillCallback,
468
+ request = fillRequest,
469
+ )
470
+
471
+ testDispatcher.scheduler.runCurrent()
472
+
473
+ // Verify
474
+ verify(exactly = 1 ) {
475
+ cancellationSignal.setOnCancelListener(any())
476
+ parser.parse(autofillAppInfo = appInfo, fillRequest = fillRequest)
477
+ fillResponseBuilder.build(
478
+ autofillAppInfo = appInfo,
479
+ filledData = filledData,
480
+ saveInfo = saveInfo,
481
+ )
482
+ fillCallback.onSuccess(fillResponse)
483
+ }
484
+ coVerify(exactly = 1 ) {
485
+ filledDataBuilder.build(autofillRequest = autofillRequest)
486
+ }
487
+ }
389
488
}
390
489
391
490
private const val PACKAGE_NAME : String = " com.google"
0 commit comments