Coverage Summary for Class: LoginUseCase (com.georgeci.moneysurfer.domain.usecase)

Class Method, % Branch, % Line, % Instruction, %
LoginUseCase 100% (2/2) 50% (1/2) 100% (24/24) 100% (297/297)
LoginUseCase$invoke$1
Total 100% (2/2) 50% (1/2) 100% (24/24) 100% (297/297)


 package com.georgeci.moneysurfer.domain.usecase
 
 import arrow.core.Either
 import arrow.core.raise.either
 import com.georgeci.moneysurfer.domain.auth.AuthError
 import com.georgeci.moneysurfer.domain.auth.AuthLocalRepository
 import com.georgeci.moneysurfer.domain.auth.SessionMutator
 import com.georgeci.moneysurfer.domain.repositories.AuthRemoteRepository
 import org.koin.core.annotation.Single
 
 @Single
 @Suppress("LongParameterList")
 class LoginUseCase(
     private val authRemoteRepository: AuthRemoteRepository,
     private val authLocalRepository: AuthLocalRepository,
     private val sessionMutator: SessionMutator,
     private val wipeDemoDataUseCase: WipeDemoDataUseCase,
     private val postAuthBootstrap: PostAuthBootstrapUseCase,
     private val abandonAuthSession: AbandonAuthSessionUseCase,
 ) {
     suspend operator fun invoke(
         email: String,
         password: String,
     ): Either<AuthError, PostAuthBootstrapUseCase.Result> = either {
         val trimmed = email.trim()
         val displayName = trimmed.ifBlank { null }
 
         val uid = authRemoteRepository.signInWithEmail(trimmed, password).bind()
 
         // Drop any demo data BEFORE pinning the real session โ€” demo rows must
         // never end up in the real account's outbox / Firestore (sync.md ยง2.11).
         wipeDemoDataUseCase()
 
         authLocalRepository.createLocalUser(
             uid = uid,
             email = trimmed,
             displayName = displayName,
             isAnon = false,
         )
         sessionMutator.setFirebaseUid(uid)
 
         // The pointers have to be live *before* the bootstrap โ€” the pull reads
         // `currentFirebaseUid` to discover the user's workspaces โ€” so atomicity is bought with a
         // rollback rather than by deferring the writes. Without it a failed bootstrap leaves a
         // signed-in session with no workspace, which the next launch routes past sign-in
         // straight into the selector with no way back (issue #342).
         postAuthBootstrap(
             uid = uid,
             email = trimmed,
             displayName = displayName,
             isAnon = false,
         ).onLeft { abandonAuthSession(isAnon = false) }.bind()
     }
 }