@@ -65,6 +65,7 @@ import java.io.InputStream
6565import java.nio.file.Files
6666import java.nio.file.Paths
6767import java.util.*
68+ import java.util.concurrent.atomic.AtomicReference
6869
6970@RunWith(RobolectricTestRunner ::class )
7071@Config(shadows = [ThreadSwitcherShadow ::class ])
@@ -118,8 +119,8 @@ public class WebAuthProviderTest {
118119 `when `(mockKeyStore.hasKeyPair()).thenReturn(false )
119120
120121 // Clear any pending results left over from previous tests
121- WebAuthProvider .pendingLoginResult.set (null )
122- WebAuthProvider .pendingLogoutResult.set (null )
122+ setPendingLoginResult (null )
123+ setPendingLogoutResult (null )
123124 }
124125
125126
@@ -3074,7 +3075,8 @@ public class WebAuthProviderTest {
30743075 @Test
30753076 public fun shouldCacheLoginResultWhenLifecycleCallbackIsDetachedOnDestroy () {
30763077 val credentials = Mockito .mock(Credentials ::class .java)
3077- WebAuthProvider .pendingLoginResult.set(null )
3078+ var capturedSuccess: Credentials ? = null
3079+ var capturedError: AuthenticationException ? = null
30783080
30793081 val lifecycleOwner = Mockito .mock(LifecycleOwner ::class .java)
30803082 val lifecycle = Mockito .mock(Lifecycle ::class .java)
@@ -3084,26 +3086,24 @@ public class WebAuthProviderTest {
30843086 delegateCallback = callback,
30853087 lifecycleOwner = lifecycleOwner,
30863088 onDetached = { success, error ->
3087- if (success != null ) WebAuthProvider .pendingLoginResult.set( WebAuthProvider . PendingResult . Success ( success))
3088- else if (error != null ) WebAuthProvider .pendingLoginResult.set( WebAuthProvider . PendingResult . Failure ( error))
3089+ capturedSuccess = success
3090+ capturedError = error
30893091 }
30903092 )
30913093
30923094 lifecycleCallback.onDestroy(lifecycleOwner)
3093-
30943095 lifecycleCallback.onSuccess(credentials)
30953096
3096- val pending = WebAuthProvider .pendingLoginResult.get()
3097- Assert .assertNotNull(pending)
3098- Assert .assertTrue(pending is WebAuthProvider .PendingResult .Success )
3099- Assert .assertEquals(credentials, (pending as WebAuthProvider .PendingResult .Success ).result)
3097+ Assert .assertEquals(credentials, capturedSuccess)
3098+ Assert .assertNull(capturedError)
31003099 verify(callback, Mockito .never()).onSuccess(any()) // old callback never called
31013100 }
31023101
31033102 @Test
31043103 public fun shouldCacheLoginFailureWhenLifecycleCallbackIsDetachedOnDestroy () {
31053104 val error = AuthenticationException (" canceled" , " User canceled" )
3106- WebAuthProvider .pendingLoginResult.set(null )
3105+ var capturedSuccess: Credentials ? = null
3106+ var capturedError: AuthenticationException ? = null
31073107
31083108 val lifecycleOwner = Mockito .mock(LifecycleOwner ::class .java)
31093109 val lifecycle = Mockito .mock(Lifecycle ::class .java)
@@ -3113,23 +3113,23 @@ public class WebAuthProviderTest {
31133113 delegateCallback = callback,
31143114 lifecycleOwner = lifecycleOwner,
31153115 onDetached = { success, detachedError ->
3116- if (success != null ) WebAuthProvider .pendingLoginResult.set( WebAuthProvider . PendingResult . Success ( success))
3117- else if (detachedError != null ) WebAuthProvider .pendingLoginResult.set( WebAuthProvider . PendingResult . Failure ( detachedError))
3116+ capturedSuccess = success
3117+ capturedError = detachedError
31183118 }
31193119 )
31203120
31213121 lifecycleCallback.onDestroy(lifecycleOwner)
31223122 lifecycleCallback.onFailure(error)
31233123
3124- val pending = WebAuthProvider .pendingLoginResult.get()
3125- Assert .assertNotNull(pending)
3126- Assert .assertTrue(pending is WebAuthProvider .PendingResult .Failure )
3124+ Assert .assertNull(capturedSuccess)
3125+ Assert .assertEquals(error, capturedError)
31273126 verify(callback, Mockito .never()).onFailure(any())
31283127 }
31293128
31303129 @Test
31313130 public fun shouldDeliverDirectlyWhenLifecycleCallbackIsAlive () {
31323131 val credentials = Mockito .mock(Credentials ::class .java)
3132+ var onDetachedCalled = false
31333133
31343134 val lifecycleOwner = Mockito .mock(LifecycleOwner ::class .java)
31353135 val lifecycle = Mockito .mock(Lifecycle ::class .java)
@@ -3138,21 +3138,19 @@ public class WebAuthProviderTest {
31383138 val lifecycleCallback = LifecycleAwareCallback <Credentials >(
31393139 delegateCallback = callback,
31403140 lifecycleOwner = lifecycleOwner,
3141- onDetached = { success, error ->
3142- if (success != null ) WebAuthProvider .pendingLoginResult.set(WebAuthProvider .PendingResult .Success (success))
3143- else if (error != null ) WebAuthProvider .pendingLoginResult.set(WebAuthProvider .PendingResult .Failure (error))
3144- }
3141+ onDetached = { _, _ -> onDetachedCalled = true }
31453142 )
31463143
31473144 lifecycleCallback.onSuccess(credentials)
31483145
31493146 verify(callback).onSuccess(credentials)
3150- Assert .assertNull( WebAuthProvider .pendingLoginResult.get() )
3147+ Assert .assertFalse(onDetachedCalled )
31513148 }
31523149
31533150 @Test
31543151 public fun shouldDeliverFailureDirectlyWhenLifecycleCallbackIsAlive () {
31553152 val error = AuthenticationException (" canceled" , " User canceled" )
3153+ var onDetachedCalled = false
31563154
31573155 val lifecycleOwner = Mockito .mock(LifecycleOwner ::class .java)
31583156 val lifecycle = Mockito .mock(Lifecycle ::class .java)
@@ -3161,21 +3159,19 @@ public class WebAuthProviderTest {
31613159 val lifecycleCallback = LifecycleAwareCallback <Credentials >(
31623160 delegateCallback = callback,
31633161 lifecycleOwner = lifecycleOwner,
3164- onDetached = { success, detachedError ->
3165- if (success != null ) WebAuthProvider .pendingLoginResult.set(WebAuthProvider .PendingResult .Success (success))
3166- else if (detachedError != null ) WebAuthProvider .pendingLoginResult.set(WebAuthProvider .PendingResult .Failure (detachedError))
3167- }
3162+ onDetached = { _, _ -> onDetachedCalled = true }
31683163 )
31693164
31703165 lifecycleCallback.onFailure(error)
31713166
31723167 verify(callback).onFailure(error)
3173- Assert .assertNull( WebAuthProvider .pendingLoginResult.get() )
3168+ Assert .assertFalse(onDetachedCalled )
31743169 }
31753170
31763171 @Test
31773172 public fun shouldCacheLogoutSuccessWhenLifecycleCallbackIsDetachedOnDestroy () {
3178- WebAuthProvider .pendingLogoutResult.set(null )
3173+ var capturedSuccess = false
3174+ var capturedError: AuthenticationException ? = null
31793175
31803176 val lifecycleOwner = Mockito .mock(LifecycleOwner ::class .java)
31813177 val lifecycle = Mockito .mock(Lifecycle ::class .java)
@@ -3184,25 +3180,25 @@ public class WebAuthProviderTest {
31843180 val lifecycleCallback = LifecycleAwareCallback <Void ?>(
31853181 delegateCallback = voidCallback,
31863182 lifecycleOwner = lifecycleOwner,
3187- onDetached = { success , error ->
3188- if (error != null ) WebAuthProvider .pendingLogoutResult.set( WebAuthProvider . PendingResult . Failure ( error))
3189- else WebAuthProvider .pendingLogoutResult.set( WebAuthProvider . PendingResult . Success (success))
3183+ onDetached = { _ , error ->
3184+ capturedError = error
3185+ if (error == null ) capturedSuccess = true
31903186 }
31913187 )
31923188
31933189 lifecycleCallback.onDestroy(lifecycleOwner)
31943190 lifecycleCallback.onSuccess(null )
31953191
3196- val pending = WebAuthProvider .pendingLogoutResult.get()
3197- Assert .assertNotNull(pending)
3198- Assert .assertTrue(pending is WebAuthProvider .PendingResult .Success )
3192+ Assert .assertTrue(capturedSuccess)
3193+ Assert .assertNull(capturedError)
31993194 verify(voidCallback, Mockito .never()).onSuccess(any())
32003195 }
32013196
32023197 @Test
32033198 public fun shouldCacheLogoutFailureWhenLifecycleCallbackIsDetachedOnDestroy () {
32043199 val error = AuthenticationException (" canceled" , " User closed the browser" )
3205- WebAuthProvider .pendingLogoutResult.set(null )
3200+ var capturedSuccess = false
3201+ var capturedError: AuthenticationException ? = null
32063202
32073203 val lifecycleOwner = Mockito .mock(LifecycleOwner ::class .java)
32083204 val lifecycle = Mockito .mock(Lifecycle ::class .java)
@@ -3211,40 +3207,38 @@ public class WebAuthProviderTest {
32113207 val lifecycleCallback = LifecycleAwareCallback <Void ?>(
32123208 delegateCallback = voidCallback,
32133209 lifecycleOwner = lifecycleOwner,
3214- onDetached = { success , detachedError ->
3215- if (detachedError != null ) WebAuthProvider .pendingLogoutResult.set( WebAuthProvider . PendingResult . Failure ( detachedError))
3216- else WebAuthProvider .pendingLogoutResult.set( WebAuthProvider . PendingResult . Success (success))
3210+ onDetached = { _ , detachedError ->
3211+ capturedError = detachedError
3212+ if (detachedError == null ) capturedSuccess = true
32173213 }
32183214 )
32193215
32203216 lifecycleCallback.onDestroy(lifecycleOwner)
32213217 lifecycleCallback.onFailure(error)
32223218
3223- val pending = WebAuthProvider .pendingLogoutResult.get()
3224- Assert .assertNotNull(pending)
3225- Assert .assertTrue(pending is WebAuthProvider .PendingResult .Failure )
3219+ Assert .assertFalse(capturedSuccess)
3220+ Assert .assertEquals(error, capturedError)
32263221 verify(voidCallback, Mockito .never()).onFailure(any())
32273222 }
32283223
32293224 @Test
32303225 public fun shouldDeliverLogoutDirectlyWhenLifecycleCallbackIsAlive () {
3226+ var onDetachedCalled = false
3227+
32313228 val lifecycleOwner = Mockito .mock(LifecycleOwner ::class .java)
32323229 val lifecycle = Mockito .mock(Lifecycle ::class .java)
32333230 Mockito .`when `(lifecycleOwner.lifecycle).thenReturn(lifecycle)
32343231
32353232 val lifecycleCallback = LifecycleAwareCallback <Void ?>(
32363233 delegateCallback = voidCallback,
32373234 lifecycleOwner = lifecycleOwner,
3238- onDetached = { success, error ->
3239- if (error != null ) WebAuthProvider .pendingLogoutResult.set(WebAuthProvider .PendingResult .Failure (error))
3240- else WebAuthProvider .pendingLogoutResult.set(WebAuthProvider .PendingResult .Success (success))
3241- }
3235+ onDetached = { _, _ -> onDetachedCalled = true }
32423236 )
32433237
32443238 lifecycleCallback.onSuccess(null )
32453239
32463240 verify(voidCallback).onSuccess(null )
3247- Assert .assertNull( WebAuthProvider .pendingLogoutResult.get() )
3241+ Assert .assertFalse(onDetachedCalled )
32483242 }
32493243
32503244 @Test
@@ -3282,27 +3276,27 @@ public class WebAuthProviderTest {
32823276 @Test
32833277 public fun shouldClearPendingLoginResultOnNewLoginStart () {
32843278 val staleCredentials = Mockito .mock(Credentials ::class .java)
3285- WebAuthProvider .pendingLoginResult.set (WebAuthProvider .PendingResult .Success (staleCredentials))
3279+ setPendingLoginResult (WebAuthProvider .PendingResult .Success (staleCredentials))
32863280
32873281 login(account).start(activity, callback)
32883282
3289- Assert .assertNull(WebAuthProvider .pendingLoginResult.get ())
3283+ Assert .assertNull(getPendingLoginResult ())
32903284 }
32913285
32923286 @Test
32933287 public fun shouldClearPendingLogoutResultOnNewLogoutStart () {
3294- WebAuthProvider .pendingLogoutResult.set (WebAuthProvider .PendingResult .Success (null ))
3288+ setPendingLogoutResult (WebAuthProvider .PendingResult .Success (null ))
32953289
32963290 logout(account).start(activity, voidCallback)
32973291
3298- Assert .assertNull(WebAuthProvider .pendingLogoutResult.get ())
3292+ Assert .assertNull(getPendingLogoutResult ())
32993293 }
33003294
33013295
33023296 @Test
33033297 public fun shouldDeliverPendingLoginResultOnResume () {
33043298 val credentials = Mockito .mock(Credentials ::class .java)
3305- WebAuthProvider .pendingLoginResult.set (WebAuthProvider .PendingResult .Success (credentials))
3299+ setPendingLoginResult (WebAuthProvider .PendingResult .Success (credentials))
33063300
33073301 val lifecycleOwner = Mockito .mock(LifecycleOwner ::class .java)
33083302 val lifecycle = Mockito .mock(Lifecycle ::class .java)
@@ -3317,13 +3311,13 @@ public class WebAuthProviderTest {
33173311 observerCaptor.firstValue.onResume(lifecycleOwner)
33183312
33193313 verify(callback).onSuccess(credentials)
3320- Assert .assertNull(WebAuthProvider .pendingLoginResult.get ())
3314+ Assert .assertNull(getPendingLoginResult ())
33213315 }
33223316
33233317 @Test
33243318 public fun shouldDeliverPendingLoginFailureOnResume () {
33253319 val error = AuthenticationException (" canceled" , " User canceled" )
3326- WebAuthProvider .pendingLoginResult.set (WebAuthProvider .PendingResult .Failure (error))
3320+ setPendingLoginResult (WebAuthProvider .PendingResult .Failure (error))
33273321
33283322 val lifecycleOwner = Mockito .mock(LifecycleOwner ::class .java)
33293323 val lifecycle = Mockito .mock(Lifecycle ::class .java)
@@ -3336,12 +3330,12 @@ public class WebAuthProviderTest {
33363330 observerCaptor.firstValue.onResume(lifecycleOwner)
33373331
33383332 verify(callback).onFailure(error)
3339- Assert .assertNull(WebAuthProvider .pendingLoginResult.get ())
3333+ Assert .assertNull(getPendingLoginResult ())
33403334 }
33413335
33423336 @Test
33433337 public fun shouldDeliverPendingLogoutResultOnResume () {
3344- WebAuthProvider .pendingLogoutResult.set (WebAuthProvider .PendingResult .Success (null ))
3338+ setPendingLogoutResult (WebAuthProvider .PendingResult .Success (null ))
33453339
33463340 val lifecycleOwner = Mockito .mock(LifecycleOwner ::class .java)
33473341 val lifecycle = Mockito .mock(Lifecycle ::class .java)
@@ -3354,13 +3348,13 @@ public class WebAuthProviderTest {
33543348 observerCaptor.firstValue.onResume(lifecycleOwner)
33553349
33563350 verify(voidCallback).onSuccess(null )
3357- Assert .assertNull(WebAuthProvider .pendingLogoutResult.get ())
3351+ Assert .assertNull(getPendingLogoutResult ())
33583352 }
33593353
33603354 @Test
33613355 public fun shouldDeliverPendingLogoutFailureOnResume () {
33623356 val error = AuthenticationException (" canceled" , " User closed the browser" )
3363- WebAuthProvider .pendingLogoutResult.set (WebAuthProvider .PendingResult .Failure (error))
3357+ setPendingLogoutResult (WebAuthProvider .PendingResult .Failure (error))
33643358
33653359 val lifecycleOwner = Mockito .mock(LifecycleOwner ::class .java)
33663360 val lifecycle = Mockito .mock(Lifecycle ::class .java)
@@ -3373,7 +3367,7 @@ public class WebAuthProviderTest {
33733367 observerCaptor.firstValue.onResume(lifecycleOwner)
33743368
33753369 verify(voidCallback).onFailure(error)
3376- Assert .assertNull(WebAuthProvider .pendingLogoutResult.get ())
3370+ Assert .assertNull(getPendingLogoutResult ())
33773371 }
33783372
33793373 @Test
@@ -3407,7 +3401,7 @@ public class WebAuthProviderTest {
34073401
34083402 @Test
34093403 public fun shouldNotDeliverLogoutResultWhenNoLogoutCallbackPassedToRegisterCallbacks () {
3410- WebAuthProvider .pendingLogoutResult.set (WebAuthProvider .PendingResult .Success (null ))
3404+ setPendingLogoutResult (WebAuthProvider .PendingResult .Success (null ))
34113405
34123406 val lifecycleOwner = Mockito .mock(LifecycleOwner ::class .java)
34133407 val lifecycle = Mockito .mock(Lifecycle ::class .java)
@@ -3421,7 +3415,36 @@ public class WebAuthProviderTest {
34213415 observerCaptor.firstValue.onResume(lifecycleOwner)
34223416
34233417 verify(voidCallback, Mockito .never()).onSuccess(any())
3424- Assert .assertNotNull(WebAuthProvider .pendingLogoutResult.get())
3418+ Assert .assertNotNull(getPendingLogoutResult())
3419+ }
3420+
3421+ // Reflection helpers — pendingLoginResult/pendingLogoutResult are private in WebAuthProvider
3422+ @Suppress(" UNCHECKED_CAST" )
3423+ private fun setPendingLoginResult (result : WebAuthProvider .PendingResult <Credentials >? ) {
3424+ val field = WebAuthProvider ::class .java.getDeclaredField(" pendingLoginResult" )
3425+ field.isAccessible = true
3426+ (field.get(WebAuthProvider ) as AtomicReference <WebAuthProvider .PendingResult <Credentials >? > ).set(result)
3427+ }
3428+
3429+ @Suppress(" UNCHECKED_CAST" )
3430+ private fun getPendingLoginResult (): WebAuthProvider .PendingResult <Credentials >? {
3431+ val field = WebAuthProvider ::class .java.getDeclaredField(" pendingLoginResult" )
3432+ field.isAccessible = true
3433+ return (field.get(WebAuthProvider ) as AtomicReference <WebAuthProvider .PendingResult <Credentials >? > ).get()
3434+ }
3435+
3436+ @Suppress(" UNCHECKED_CAST" )
3437+ private fun setPendingLogoutResult (result : WebAuthProvider .PendingResult <Void ?>? ) {
3438+ val field = WebAuthProvider ::class .java.getDeclaredField(" pendingLogoutResult" )
3439+ field.isAccessible = true
3440+ (field.get(WebAuthProvider ) as AtomicReference <WebAuthProvider .PendingResult <Void ?>? > ).set(result)
3441+ }
3442+
3443+ @Suppress(" UNCHECKED_CAST" )
3444+ private fun getPendingLogoutResult (): WebAuthProvider .PendingResult <Void ?>? {
3445+ val field = WebAuthProvider ::class .java.getDeclaredField(" pendingLogoutResult" )
3446+ field.isAccessible = true
3447+ return (field.get(WebAuthProvider ) as AtomicReference <WebAuthProvider .PendingResult <Void ?>? > ).get()
34253448 }
34263449
34273450 private companion object {
0 commit comments