Skip to content

Commit bad15cf

Browse files
committed
test: PhoneAuthProvider unit tests, remove mockStatic usage
1 parent 81c7120 commit bad15cf

File tree

5 files changed

+567
-93
lines changed

5 files changed

+567
-93
lines changed

auth/src/main/java/com/firebase/ui/auth/compose/configuration/auth_provider/AuthProvider.kt

Lines changed: 107 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import com.firebase.ui.auth.util.data.PhoneNumberUtils
3030
import com.firebase.ui.auth.util.data.ProviderAvailability
3131
import com.google.firebase.FirebaseException
3232
import com.google.firebase.auth.ActionCodeSettings
33+
import com.google.firebase.auth.AuthCredential
3334
import com.google.firebase.auth.EmailAuthProvider
3435
import com.google.firebase.auth.FacebookAuthProvider
3536
import com.google.firebase.auth.FirebaseAuth
@@ -271,6 +272,24 @@ abstract class AuthProvider(open val providerId: String) {
271272

272273
private fun continueUrl(continueUrl: String, block: ContinueUrlBuilder.() -> Unit) =
273274
ContinueUrlBuilder(continueUrl).apply(block).build()
275+
276+
/**
277+
* An interface to wrap the static `EmailAuthProvider.getCredential` method to make it testable.
278+
* @suppress
279+
*/
280+
internal interface CredentialProvider {
281+
fun getCredential(email: String, password: String): AuthCredential
282+
}
283+
284+
/**
285+
* The default implementation of [CredentialProvider] that calls the static method.
286+
* @suppress
287+
*/
288+
internal class DefaultCredentialProvider : CredentialProvider {
289+
override fun getCredential(email: String, password: String): AuthCredential {
290+
return EmailAuthProvider.getCredential(email, password)
291+
}
292+
}
274293
}
275294

276295
/**
@@ -388,40 +407,99 @@ abstract class AuthProvider(open val providerId: String) {
388407
phoneNumber: String,
389408
multiFactorSession: MultiFactorSession? = null,
390409
forceResendingToken: PhoneAuthProvider.ForceResendingToken?,
391-
): VerifyPhoneNumberResult = suspendCoroutine { continuation ->
392-
val options = PhoneAuthOptions.newBuilder(auth)
393-
.setPhoneNumber(phoneNumber)
394-
.requireSmsValidation(!isInstantVerificationEnabled)
395-
.setTimeout(timeout, TimeUnit.SECONDS)
396-
.setCallbacks(object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
397-
override fun onVerificationCompleted(credential: PhoneAuthCredential) {
398-
continuation.resume(VerifyPhoneNumberResult.AutoVerified(credential))
399-
}
410+
verifier: Verifier = DefaultVerifier(),
411+
): VerifyPhoneNumberResult {
412+
return verifier.verifyPhoneNumber(
413+
auth,
414+
phoneNumber,
415+
timeout,
416+
forceResendingToken,
417+
multiFactorSession,
418+
isInstantVerificationEnabled
419+
)
420+
}
400421

401-
override fun onVerificationFailed(e: FirebaseException) {
402-
continuation.resumeWithException(e)
403-
}
422+
/**
423+
* @suppress
424+
*/
425+
internal interface Verifier {
426+
suspend fun verifyPhoneNumber(
427+
auth: FirebaseAuth,
428+
phoneNumber: String,
429+
timeout: Long,
430+
forceResendingToken: PhoneAuthProvider.ForceResendingToken?,
431+
multiFactorSession: MultiFactorSession?,
432+
isInstantVerificationEnabled: Boolean
433+
): VerifyPhoneNumberResult
434+
}
404435

405-
override fun onCodeSent(
406-
verificationId: String,
407-
token: PhoneAuthProvider.ForceResendingToken,
408-
) {
409-
continuation.resume(
410-
VerifyPhoneNumberResult.NeedsManualVerification(
411-
verificationId,
412-
token
413-
)
414-
)
436+
/**
437+
* @suppress
438+
*/
439+
internal class DefaultVerifier : Verifier {
440+
override suspend fun verifyPhoneNumber(
441+
auth: FirebaseAuth,
442+
phoneNumber: String,
443+
timeout: Long,
444+
forceResendingToken: PhoneAuthProvider.ForceResendingToken?,
445+
multiFactorSession: MultiFactorSession?,
446+
isInstantVerificationEnabled: Boolean
447+
): VerifyPhoneNumberResult {
448+
return suspendCoroutine { continuation ->
449+
val options = PhoneAuthOptions.newBuilder(auth)
450+
.setPhoneNumber(phoneNumber)
451+
.requireSmsValidation(!isInstantVerificationEnabled)
452+
.setTimeout(timeout, TimeUnit.SECONDS)
453+
.setCallbacks(object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
454+
override fun onVerificationCompleted(credential: PhoneAuthCredential) {
455+
continuation.resume(VerifyPhoneNumberResult.AutoVerified(credential))
456+
}
457+
458+
override fun onVerificationFailed(e: FirebaseException) {
459+
continuation.resumeWithException(e)
460+
}
461+
462+
override fun onCodeSent(
463+
verificationId: String,
464+
token: PhoneAuthProvider.ForceResendingToken,
465+
) {
466+
continuation.resume(
467+
VerifyPhoneNumberResult.NeedsManualVerification(
468+
verificationId,
469+
token
470+
)
471+
)
472+
}
473+
})
474+
if (forceResendingToken != null) {
475+
options.setForceResendingToken(forceResendingToken)
415476
}
416-
})
417-
if (forceResendingToken != null) {
418-
options.setForceResendingToken(forceResendingToken)
477+
if (multiFactorSession != null) {
478+
options.setMultiFactorSession(multiFactorSession)
479+
}
480+
PhoneAuthProvider.verifyPhoneNumber(options.build())
481+
}
419482
}
420-
if (multiFactorSession != null) {
421-
options.setMultiFactorSession(multiFactorSession)
483+
}
484+
485+
/**
486+
* An interface to wrap the static `PhoneAuthProvider.getCredential` method to make it testable.
487+
* @suppress
488+
*/
489+
internal interface CredentialProvider {
490+
fun getCredential(verificationId: String, smsCode: String): PhoneAuthCredential
491+
}
492+
493+
/**
494+
* The default implementation of [CredentialProvider] that calls the static method.
495+
* @suppress
496+
*/
497+
internal class DefaultCredentialProvider : CredentialProvider {
498+
override fun getCredential(verificationId: String, smsCode: String): PhoneAuthCredential {
499+
return PhoneAuthProvider.getCredential(verificationId, smsCode)
422500
}
423-
PhoneAuthProvider.verifyPhoneNumber(options.build())
424501
}
502+
425503
}
426504

427505
/**
@@ -704,4 +782,4 @@ abstract class AuthProvider(open val providerId: String) {
704782
}
705783
}
706784
}
707-
}
785+
}

auth/src/main/java/com/firebase/ui/auth/compose/configuration/auth_provider/EmailAuthProvider+FirebaseAuthUI.kt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ import kotlinx.coroutines.tasks.await
5050
internal class CredentialForLinking(
5151
val providerType: String,
5252
val idToken: String?,
53-
val accessToken: String?
53+
val accessToken: String?,
5454
)
5555

5656
/**
@@ -130,11 +130,12 @@ internal suspend fun FirebaseAuthUI.createOrLinkUserWithEmailAndPassword(
130130
provider: AuthProvider.Email,
131131
name: String?,
132132
email: String,
133-
password: String
133+
password: String,
134+
credentialProvider: AuthProvider.Email.CredentialProvider = AuthProvider.Email.DefaultCredentialProvider(),
134135
): AuthResult? {
135136
val canUpgrade = canUpgradeAnonymous(config, auth)
136137
val pendingCredential =
137-
if (canUpgrade) EmailAuthProvider.getCredential(email, password) else null
138+
if (canUpgrade) credentialProvider.getCredential(email, password) else null
138139

139140
try {
140141
// Check if new accounts are allowed (only for non-upgrade flows)
@@ -454,7 +455,7 @@ internal suspend fun FirebaseAuthUI.signInAndLinkWithCredential(
454455
config: AuthUIConfiguration,
455456
credential: AuthCredential,
456457
displayName: String? = null,
457-
photoUrl: Uri? = null
458+
photoUrl: Uri? = null,
458459
): AuthResult? {
459460
try {
460461
updateAuthState(AuthState.Loading("Signing in user..."))
@@ -639,7 +640,7 @@ internal suspend fun FirebaseAuthUI.sendSignInLinkToEmail(
639640
config: AuthUIConfiguration,
640641
provider: AuthProvider.Email,
641642
email: String,
642-
credentialForLinking: CredentialForLinking? = null
643+
credentialForLinking: CredentialForLinking? = null,
643644
) {
644645
try {
645646
updateAuthState(AuthState.Loading("Sending sign in email link..."))
@@ -938,7 +939,7 @@ suspend fun FirebaseAuthUI.signInWithEmailLink(
938939
*/
939940
internal suspend fun FirebaseAuthUI.sendPasswordResetEmail(
940941
email: String,
941-
actionCodeSettings: ActionCodeSettings? = null
942+
actionCodeSettings: ActionCodeSettings? = null,
942943
) {
943944
try {
944945
updateAuthState(AuthState.Loading("Sending password reset email..."))

auth/src/main/java/com/firebase/ui/auth/compose/configuration/auth_provider/PhoneAuthProvider+FirebaseAuthUI.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,16 @@ internal suspend fun FirebaseAuthUI.verifyPhoneNumber(
104104
phoneNumber: String,
105105
multiFactorSession: MultiFactorSession? = null,
106106
forceResendingToken: PhoneAuthProvider.ForceResendingToken? = null,
107+
verifier: AuthProvider.Phone.Verifier = AuthProvider.Phone.DefaultVerifier(),
107108
) {
108109
try {
109110
updateAuthState(AuthState.Loading("Verifying phone number..."))
110111
val result = provider.verifyPhoneNumberAwait(
111112
auth = auth,
112113
phoneNumber = phoneNumber,
113114
multiFactorSession = multiFactorSession,
114-
forceResendingToken = forceResendingToken
115+
forceResendingToken = forceResendingToken,
116+
verifier = verifier
115117
)
116118
when (result) {
117119
is AuthProvider.Phone.VerifyPhoneNumberResult.AutoVerified -> {
@@ -195,10 +197,11 @@ internal suspend fun FirebaseAuthUI.submitVerificationCode(
195197
config: AuthUIConfiguration,
196198
verificationId: String,
197199
code: String,
200+
credentialProvider: AuthProvider.Phone.CredentialProvider = AuthProvider.Phone.DefaultCredentialProvider(),
198201
): AuthResult? {
199202
try {
200203
updateAuthState(AuthState.Loading("Submitting verification code..."))
201-
val credential = PhoneAuthProvider.getCredential(verificationId, code)
204+
val credential = credentialProvider.getCredential(verificationId, code)
202205
return signInWithPhoneAuthCredential(
203206
config = config,
204207
credential = credential

0 commit comments

Comments
 (0)