BIT-653: Adding data source for passphrase generation (#273)

This commit is contained in:
joshua-livefront 2023-11-22 18:22:56 -05:00 committed by Álison Fernandes
parent 3a07bbd3da
commit 1f337e94f0
14 changed files with 266 additions and 72 deletions

View file

@ -1,6 +1,6 @@
package com.x8bit.bitwarden.data.tools.generator.datasource.disk
import com.x8bit.bitwarden.data.tools.generator.repository.model.PasswordGenerationOptions
import com.x8bit.bitwarden.data.tools.generator.repository.model.PasscodeGenerationOptions
/**
* Primary access point for disk information related to generation.
@ -8,12 +8,12 @@ import com.x8bit.bitwarden.data.tools.generator.repository.model.PasswordGenerat
interface GeneratorDiskSource {
/**
* Retrieves a user's password generation options using a [userId].
* Retrieves a user's passcode generation options using a [userId].
*/
fun getPasswordGenerationOptions(userId: String): PasswordGenerationOptions?
fun getPasscodeGenerationOptions(userId: String): PasscodeGenerationOptions?
/**
* Stores a user's password generation options using a [userId].
* Stores a user's passcode generation options using a [userId].
*/
fun storePasswordGenerationOptions(userId: String, options: PasswordGenerationOptions?)
fun storePasscodeGenerationOptions(userId: String, options: PasscodeGenerationOptions?)
}

View file

@ -2,7 +2,7 @@ package com.x8bit.bitwarden.data.tools.generator.datasource.disk
import android.content.SharedPreferences
import com.x8bit.bitwarden.data.platform.datasource.disk.BaseDiskSource
import com.x8bit.bitwarden.data.tools.generator.repository.model.PasswordGenerationOptions
import com.x8bit.bitwarden.data.tools.generator.repository.model.PasscodeGenerationOptions
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
@ -17,14 +17,14 @@ class GeneratorDiskSourceImpl(
) : BaseDiskSource(sharedPreferences),
GeneratorDiskSource {
override fun getPasswordGenerationOptions(userId: String): PasswordGenerationOptions? {
override fun getPasscodeGenerationOptions(userId: String): PasscodeGenerationOptions? {
val key = getPasswordGenerationOptionsKey(userId)
return getString(key)?.let { json.decodeFromString(it) }
}
override fun storePasswordGenerationOptions(
override fun storePasscodeGenerationOptions(
userId: String,
options: PasswordGenerationOptions?,
options: PasscodeGenerationOptions?,
) {
val key = getPasswordGenerationOptionsKey(userId)
putString(

View file

@ -1,5 +1,6 @@
package com.x8bit.bitwarden.data.tools.generator.datasource.sdk
import com.bitwarden.core.PassphraseGeneratorRequest
import com.bitwarden.core.PasswordGeneratorRequest
/**
@ -11,4 +12,9 @@ interface GeneratorSdkSource {
* Generates a password returning a [String] wrapped in a [Result].
*/
suspend fun generatePassword(request: PasswordGeneratorRequest): Result<String>
/**
* Generates a passphrase returning a [String] wrapped in a [Result].
*/
suspend fun generatePassphrase(request: PassphraseGeneratorRequest): Result<String>
}

View file

@ -1,5 +1,6 @@
package com.x8bit.bitwarden.data.tools.generator.datasource.sdk
import com.bitwarden.core.PassphraseGeneratorRequest
import com.bitwarden.core.PasswordGeneratorRequest
import com.bitwarden.sdk.ClientGenerators
@ -17,4 +18,10 @@ class GeneratorSdkSourceImpl(
): Result<String> = runCatching {
clientGenerator.password(request)
}
override suspend fun generatePassphrase(
request: PassphraseGeneratorRequest,
): Result<String> = runCatching {
clientGenerator.passphrase(request)
}
}

View file

@ -1,8 +1,10 @@
package com.x8bit.bitwarden.data.tools.generator.repository
import com.bitwarden.core.PassphraseGeneratorRequest
import com.bitwarden.core.PasswordGeneratorRequest
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedPassphraseResult
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedPasswordResult
import com.x8bit.bitwarden.data.tools.generator.repository.model.PasswordGenerationOptions
import com.x8bit.bitwarden.data.tools.generator.repository.model.PasscodeGenerationOptions
/**
* Responsible for managing generator data.
@ -17,12 +19,19 @@ interface GeneratorRepository {
): GeneratedPasswordResult
/**
* Get the [PasswordGenerationOptions] for the current user.
* Attempt to generate a passphrase.
*/
fun getPasswordGenerationOptions(): PasswordGenerationOptions?
suspend fun generatePassphrase(
passphraseGeneratorRequest: PassphraseGeneratorRequest,
): GeneratedPassphraseResult
/**
* Save the [PasswordGenerationOptions] for the current user.
* Get the [PasscodeGenerationOptions] for the current user.
*/
fun savePasswordGenerationOptions(options: PasswordGenerationOptions)
fun getPasscodeGenerationOptions(): PasscodeGenerationOptions?
/**
* Save the [PasscodeGenerationOptions] for the current user.
*/
fun savePasscodeGenerationOptions(options: PasscodeGenerationOptions)
}

View file

@ -1,11 +1,13 @@
package com.x8bit.bitwarden.data.tools.generator.repository
import com.bitwarden.core.PassphraseGeneratorRequest
import com.bitwarden.core.PasswordGeneratorRequest
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
import com.x8bit.bitwarden.data.tools.generator.datasource.disk.GeneratorDiskSource
import com.x8bit.bitwarden.data.tools.generator.datasource.sdk.GeneratorSdkSource
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedPassphraseResult
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedPasswordResult
import com.x8bit.bitwarden.data.tools.generator.repository.model.PasswordGenerationOptions
import com.x8bit.bitwarden.data.tools.generator.repository.model.PasscodeGenerationOptions
import javax.inject.Singleton
/**
@ -28,13 +30,23 @@ class GeneratorRepositoryImpl constructor(
onFailure = { GeneratedPasswordResult.InvalidRequest },
)
override fun getPasswordGenerationOptions(): PasswordGenerationOptions? {
override suspend fun generatePassphrase(
passphraseGeneratorRequest: PassphraseGeneratorRequest,
): GeneratedPassphraseResult =
generatorSdkSource
.generatePassphrase(passphraseGeneratorRequest)
.fold(
onSuccess = { GeneratedPassphraseResult.Success(it) },
onFailure = { GeneratedPassphraseResult.InvalidRequest },
)
override fun getPasscodeGenerationOptions(): PasscodeGenerationOptions? {
val userId = authDiskSource.userState?.activeUserId
return userId?.let { generatorDiskSource.getPasswordGenerationOptions(it) }
return userId?.let { generatorDiskSource.getPasscodeGenerationOptions(it) }
}
override fun savePasswordGenerationOptions(options: PasswordGenerationOptions) {
override fun savePasscodeGenerationOptions(options: PasscodeGenerationOptions) {
val userId = authDiskSource.userState?.activeUserId
userId?.let { generatorDiskSource.storePasswordGenerationOptions(it, options) }
userId?.let { generatorDiskSource.storePasscodeGenerationOptions(it, options) }
}
}

View file

@ -0,0 +1,16 @@
package com.x8bit.bitwarden.data.tools.generator.repository.model
/**
* Represents the outcome of a generator operation.
*/
sealed class GeneratedPassphraseResult {
/**
* Operation succeeded with a value.
*/
data class Success(val generatedString: String) : GeneratedPassphraseResult()
/**
* There was an error during the operation.
*/
data object InvalidRequest : GeneratedPassphraseResult()
}

View file

@ -4,7 +4,7 @@ import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* A data class representing the configuration options for password generation.
* A data class representing the configuration options for both password and passphrase generation.
*
* @property length The total length of the generated password.
* @property allowAmbiguousChar Indicates whether ambiguous characters are allowed in the password.
@ -16,9 +16,16 @@ import kotlinx.serialization.Serializable
* @property minLowercase The minimum number of lowercase characters required in the password.
* @property allowSpecial Indicates whether special characters are allowed in the password.
* @property minSpecial The minimum number of special characters required in the password.
* @property numWords The number of words in the generated passphrase.
* @property wordSeparator The character used to separate words in the passphrase.
* @property allowCapitalize Indicates whether to use capitals in the passphrase.
* @property allowIncludeNumber Indicates whether to include numbers in the passphrase.
*/
@Serializable
data class PasswordGenerationOptions(
data class PasscodeGenerationOptions(
// Password-specific options
@SerialName("length")
val length: Int,
@ -35,17 +42,31 @@ data class PasswordGenerationOptions(
val hasUppercase: Boolean,
@SerialName("minUppercase")
val minUppercase: Int?,
val minUppercase: Int? = null,
@SerialName("lowercase")
val hasLowercase: Boolean,
@SerialName("minLowercase")
val minLowercase: Int?,
val minLowercase: Int? = null,
@SerialName("special")
val allowSpecial: Boolean,
@SerialName("minSpecial")
val minSpecial: Int,
// Passphrase-specific options
@SerialName("numWords")
val numWords: Int,
@SerialName("wordSeparator")
val wordSeparator: String,
@SerialName("capitalize")
val allowCapitalize: Boolean,
@SerialName("includeNumber")
val allowIncludeNumber: Boolean,
)

View file

@ -9,7 +9,7 @@ import com.bitwarden.core.PasswordGeneratorRequest
import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.data.tools.generator.repository.GeneratorRepository
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedPasswordResult
import com.x8bit.bitwarden.data.tools.generator.repository.model.PasswordGenerationOptions
import com.x8bit.bitwarden.data.tools.generator.repository.model.PasscodeGenerationOptions
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
import com.x8bit.bitwarden.ui.platform.base.util.Text
import com.x8bit.bitwarden.ui.platform.base.util.asText
@ -104,7 +104,7 @@ class GeneratorViewModel @Inject constructor(
}
is Password -> {
val options = generatorRepository.getPasswordGenerationOptions()
val options = generatorRepository.getPasscodeGenerationOptions()
val password = if (options != null) {
Password(
length = options.length,
@ -134,19 +134,39 @@ class GeneratorViewModel @Inject constructor(
}
private fun savePasswordOptionsToDisk(password: Password) {
val options = PasswordGenerationOptions(
val options = generatorRepository
.getPasscodeGenerationOptions() ?: generatePasscodeDefaultOptions()
val newOptions = options.copy(
length = password.length,
allowAmbiguousChar = password.avoidAmbiguousChars,
hasNumbers = password.useNumbers,
minNumber = password.minNumbers,
hasUppercase = password.useCapitals,
minUppercase = null,
hasLowercase = password.useLowercase,
minLowercase = null,
allowSpecial = password.useSpecialChars,
minSpecial = password.minSpecial,
)
generatorRepository.savePasswordGenerationOptions(options)
generatorRepository.savePasscodeGenerationOptions(newOptions)
}
private fun generatePasscodeDefaultOptions(): PasscodeGenerationOptions {
val defaultPassword = Password()
val defaultPassphrase = Passphrase()
return PasscodeGenerationOptions(
length = defaultPassword.length,
allowAmbiguousChar = defaultPassword.avoidAmbiguousChars,
hasNumbers = defaultPassword.useNumbers,
minNumber = defaultPassword.minNumbers,
hasUppercase = defaultPassword.useCapitals,
hasLowercase = defaultPassword.useLowercase,
allowSpecial = defaultPassword.useSpecialChars,
minSpecial = defaultPassword.minSpecial,
allowCapitalize = defaultPassphrase.capitalize,
allowIncludeNumber = defaultPassphrase.includeNumber,
wordSeparator = defaultPassphrase.wordSeparator.toString(),
numWords = defaultPassphrase.numWords,
)
}
private suspend fun generatePassword(password: Password) {

View file

@ -1,6 +1,6 @@
package com.x8bit.bitwarden.data.tools.generator.datasource.disk
import com.x8bit.bitwarden.data.tools.generator.repository.model.PasswordGenerationOptions
import com.x8bit.bitwarden.data.tools.generator.repository.model.PasscodeGenerationOptions
import com.x8bit.bitwarden.data.platform.base.FakeSharedPreferences
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.encodeToString
@ -25,9 +25,9 @@ class GeneratorDiskSourceTest {
)
@Test
fun `getPasswordGenerationOptions should return correct options when available`() {
fun `getPasscodeGenerationOptions should return correct options when available`() {
val userId = "user123"
val options = PasswordGenerationOptions(
val options = PasscodeGenerationOptions(
length = 14,
allowAmbiguousChar = false,
hasNumbers = true,
@ -38,29 +38,33 @@ class GeneratorDiskSourceTest {
minLowercase = null,
allowSpecial = false,
minSpecial = 1,
allowCapitalize = false,
allowIncludeNumber = false,
wordSeparator = "-",
numWords = 3,
)
val key = "bwPreferencesStorage_passwordGenerationOptions_$userId"
fakeSharedPreferences.edit().putString(key, json.encodeToString(options)).apply()
val result = generatorDiskSource.getPasswordGenerationOptions(userId)
val result = generatorDiskSource.getPasscodeGenerationOptions(userId)
assertEquals(options, result)
}
@Test
fun `getPasswordGenerationOptions should return null when options are not available`() {
fun `getPasscodeGenerationOptions should return null when options are not available`() {
val userId = "user123"
val result = generatorDiskSource.getPasswordGenerationOptions(userId)
val result = generatorDiskSource.getPasscodeGenerationOptions(userId)
assertNull(result)
}
@Test
fun `storePasswordGenerationOptions should correctly store options`() {
fun `storePasscodeGenerationOptions should correctly store options`() {
val userId = "user123"
val options = PasswordGenerationOptions(
val options = PasscodeGenerationOptions(
length = 14,
allowAmbiguousChar = false,
hasNumbers = true,
@ -71,11 +75,15 @@ class GeneratorDiskSourceTest {
minLowercase = null,
allowSpecial = false,
minSpecial = 1,
allowCapitalize = false,
allowIncludeNumber = false,
wordSeparator = "-",
numWords = 3,
)
val key = "bwPreferencesStorage_passwordGenerationOptions_$userId"
generatorDiskSource.storePasswordGenerationOptions(userId, options)
generatorDiskSource.storePasscodeGenerationOptions(userId, options)
val storedValue = fakeSharedPreferences.getString(key, null)
assertNotNull(storedValue)

View file

@ -1,5 +1,6 @@
package com.x8bit.bitwarden.data.tools.generator.datasource.sdk
import com.bitwarden.core.PassphraseGeneratorRequest
import com.bitwarden.core.PasswordGeneratorRequest
import com.bitwarden.sdk.ClientGenerators
import io.mockk.coEvery
@ -42,4 +43,28 @@ class GeneratorSdkSourceTest {
clientGenerators.password(request)
}
}
@Suppress("MaxLineLength")
@Test
fun `generatePassphrase should call SDK and return a Result with the generated passphrase`() = runBlocking {
val request = PassphraseGeneratorRequest(
numWords = 4.toUByte(),
wordSeparator = "-",
capitalize = true,
includeNumber = true,
)
val expectedResult = "Generated-Passphrase123"
coEvery {
clientGenerators.passphrase(request)
} returns expectedResult
val result = generatorSdkSource.generatePassphrase(request)
assertEquals(Result.success(expectedResult), result)
coVerify {
clientGenerators.passphrase(request)
}
}
}

View file

@ -1,5 +1,6 @@
package com.x8bit.bitwarden.data.tools.generator.repository
import com.bitwarden.core.PassphraseGeneratorRequest
import com.bitwarden.core.PasswordGeneratorRequest
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
import com.x8bit.bitwarden.data.auth.datasource.disk.model.AccountJson
@ -12,8 +13,9 @@ import com.x8bit.bitwarden.data.auth.datasource.network.model.TrustedDeviceUserD
import com.x8bit.bitwarden.data.auth.datasource.network.model.UserDecryptionOptionsJson
import com.x8bit.bitwarden.data.tools.generator.datasource.disk.GeneratorDiskSource
import com.x8bit.bitwarden.data.tools.generator.datasource.sdk.GeneratorSdkSource
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedPassphraseResult
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedPasswordResult
import com.x8bit.bitwarden.data.tools.generator.repository.model.PasswordGenerationOptions
import com.x8bit.bitwarden.data.tools.generator.repository.model.PasscodeGenerationOptions
import io.mockk.Runs
import io.mockk.clearMocks
import io.mockk.coEvery
@ -93,9 +95,49 @@ class GeneratorRepositoryTest {
}
@Test
fun `getPasswordGenerationOptions should return options when available`() = runTest {
fun `generatePassphrase should emit Success result with the generated passphrase`() = runTest {
val request = PassphraseGeneratorRequest(
numWords = 5.toUByte(),
capitalize = true,
includeNumber = true,
wordSeparator = '-'.toString(),
)
val expectedResult = "Generated-Passphrase-123!"
coEvery {
generatorSdkSource.generatePassphrase(request)
} returns Result.success(expectedResult)
val result = repository.generatePassphrase(request)
assertEquals(expectedResult, (result as GeneratedPassphraseResult.Success).generatedString)
coVerify { generatorSdkSource.generatePassphrase(request) }
}
@Suppress("MaxLineLength")
@Test
fun `generatePassphrase should emit InvalidRequest result when SDK throws exception`() =
runTest {
val request = PassphraseGeneratorRequest(
numWords = 5.toUByte(),
capitalize = true,
includeNumber = true,
wordSeparator = '-'.toString(),
)
val exception = RuntimeException("An error occurred")
coEvery { generatorSdkSource.generatePassphrase(request) } returns Result.failure(
exception,
)
val result = repository.generatePassphrase(request)
assertTrue(result is GeneratedPassphraseResult.InvalidRequest)
coVerify { generatorSdkSource.generatePassphrase(request) }
}
@Test
fun `getPasscodeGenerationOptions should return options when available`() = runTest {
val userId = "activeUserId"
val expectedOptions = PasswordGenerationOptions(
val expectedOptions = PasscodeGenerationOptions(
length = 14,
allowAmbiguousChar = false,
hasNumbers = true,
@ -106,47 +148,51 @@ class GeneratorRepositoryTest {
minLowercase = null,
allowSpecial = false,
minSpecial = 1,
allowCapitalize = false,
allowIncludeNumber = false,
wordSeparator = "-",
numWords = 3,
)
coEvery { authDiskSource.userState } returns USER_STATE
coEvery {
generatorDiskSource.getPasswordGenerationOptions(userId)
generatorDiskSource.getPasscodeGenerationOptions(userId)
} returns expectedOptions
val result = repository.getPasswordGenerationOptions()
val result = repository.getPasscodeGenerationOptions()
assertEquals(expectedOptions, result)
coVerify { generatorDiskSource.getPasswordGenerationOptions(userId) }
coVerify { generatorDiskSource.getPasscodeGenerationOptions(userId) }
}
@Test
fun `getPasswordGenerationOptions should return null when there is no active user`() = runTest {
fun `getPasscodeGenerationOptions should return null when there is no active user`() = runTest {
coEvery { authDiskSource.userState } returns null
val result = repository.getPasswordGenerationOptions()
val result = repository.getPasscodeGenerationOptions()
assertNull(result)
coVerify(exactly = 0) { generatorDiskSource.getPasswordGenerationOptions(any()) }
coVerify(exactly = 0) { generatorDiskSource.getPasscodeGenerationOptions(any()) }
}
@Suppress("MaxLineLength")
@Test
fun `getPasswordGenerationOptions should return null when no data is stored for active user`() = runTest {
fun `getPasscodeGenerationOptions should return null when no data is stored for active user`() = runTest {
val userId = "activeUserId"
coEvery { authDiskSource.userState } returns USER_STATE
coEvery { generatorDiskSource.getPasswordGenerationOptions(userId) } returns null
coEvery { generatorDiskSource.getPasscodeGenerationOptions(userId) } returns null
val result = repository.getPasswordGenerationOptions()
val result = repository.getPasscodeGenerationOptions()
assertNull(result)
coVerify { generatorDiskSource.getPasswordGenerationOptions(userId) }
coVerify { generatorDiskSource.getPasscodeGenerationOptions(userId) }
}
@Test
fun `savePasswordGenerationOptions should store options correctly`() = runTest {
fun `savePasscodeGenerationOptions should store options correctly`() = runTest {
val userId = "activeUserId"
val optionsToSave = PasswordGenerationOptions(
val optionsToSave = PasscodeGenerationOptions(
length = 14,
allowAmbiguousChar = false,
hasNumbers = true,
@ -157,23 +203,27 @@ class GeneratorRepositoryTest {
minLowercase = null,
allowSpecial = false,
minSpecial = 1,
allowCapitalize = false,
allowIncludeNumber = false,
wordSeparator = "-",
numWords = 3,
)
coEvery { authDiskSource.userState } returns USER_STATE
coEvery {
generatorDiskSource.storePasswordGenerationOptions(userId, optionsToSave)
generatorDiskSource.storePasscodeGenerationOptions(userId, optionsToSave)
} just Runs
repository.savePasswordGenerationOptions(optionsToSave)
repository.savePasscodeGenerationOptions(optionsToSave)
coVerify { generatorDiskSource.storePasswordGenerationOptions(userId, optionsToSave) }
coVerify { generatorDiskSource.storePasscodeGenerationOptions(userId, optionsToSave) }
}
@Suppress("MaxLineLength")
@Test
fun `savePasswordGenerationOptions should not store options when there is no active user`() = runTest {
val optionsToSave = PasswordGenerationOptions(
fun `savePasscodeGenerationOptions should not store options when there is no active user`() = runTest {
val optionsToSave = PasscodeGenerationOptions(
length = 14,
allowAmbiguousChar = false,
hasNumbers = true,
@ -184,13 +234,17 @@ class GeneratorRepositoryTest {
minLowercase = null,
allowSpecial = false,
minSpecial = 1,
allowCapitalize = false,
allowIncludeNumber = false,
wordSeparator = "-",
numWords = 3,
)
coEvery { authDiskSource.userState } returns null
repository.savePasswordGenerationOptions(optionsToSave)
repository.savePasscodeGenerationOptions(optionsToSave)
coVerify(exactly = 0) { generatorDiskSource.storePasswordGenerationOptions(any(), any()) }
coVerify(exactly = 0) { generatorDiskSource.storePasscodeGenerationOptions(any(), any()) }
}
private val USER_STATE = UserStateJson(

View file

@ -1,9 +1,11 @@
package com.x8bit.bitwarden.data.tools.generator.repository.util
import com.bitwarden.core.PassphraseGeneratorRequest
import com.bitwarden.core.PasswordGeneratorRequest
import com.x8bit.bitwarden.data.tools.generator.repository.GeneratorRepository
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedPassphraseResult
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedPasswordResult
import com.x8bit.bitwarden.data.tools.generator.repository.model.PasswordGenerationOptions
import com.x8bit.bitwarden.data.tools.generator.repository.model.PasscodeGenerationOptions
/**
* A fake implementation of [GeneratorRepository] for testing purposes.
@ -13,7 +15,11 @@ class FakeGeneratorRepository : GeneratorRepository {
private var generatePasswordResult: GeneratedPasswordResult = GeneratedPasswordResult.Success(
generatedString = "updatedText",
)
private var passwordGenerationOptions: PasswordGenerationOptions? = null
private var generatePassphraseResult: GeneratedPassphraseResult =
GeneratedPassphraseResult.Success(
generatedString = "updatedPassphrase",
)
private var passcodeGenerationOptions: PasscodeGenerationOptions? = null
override suspend fun generatePassword(
passwordGeneratorRequest: PasswordGeneratorRequest,
@ -21,12 +27,18 @@ class FakeGeneratorRepository : GeneratorRepository {
return generatePasswordResult
}
override fun getPasswordGenerationOptions(): PasswordGenerationOptions? {
return passwordGenerationOptions
override suspend fun generatePassphrase(
passphraseGeneratorRequest: PassphraseGeneratorRequest,
): GeneratedPassphraseResult {
return generatePassphraseResult
}
override fun savePasswordGenerationOptions(options: PasswordGenerationOptions) {
passwordGenerationOptions = options
override fun getPasscodeGenerationOptions(): PasscodeGenerationOptions? {
return passcodeGenerationOptions
}
override fun savePasscodeGenerationOptions(options: PasscodeGenerationOptions) {
passcodeGenerationOptions = options
}
/**
@ -37,9 +49,9 @@ class FakeGeneratorRepository : GeneratorRepository {
}
/**
* Sets the mock password generation options.
* Sets the mock result for the generatePassphrase function.
*/
fun setMockGeneratePasswordGenerationOptions(options: PasswordGenerationOptions?) {
passwordGenerationOptions = options
fun setMockGeneratePassphraseResult(result: GeneratedPassphraseResult) {
generatePassphraseResult = result
}
}

View file

@ -4,7 +4,7 @@ import androidx.lifecycle.SavedStateHandle
import app.cash.turbine.test
import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedPasswordResult
import com.x8bit.bitwarden.data.tools.generator.repository.model.PasswordGenerationOptions
import com.x8bit.bitwarden.data.tools.generator.repository.model.PasscodeGenerationOptions
import com.x8bit.bitwarden.data.tools.generator.repository.util.FakeGeneratorRepository
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
import com.x8bit.bitwarden.ui.platform.base.util.asText
@ -48,7 +48,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
val viewModel = createViewModel()
val initialState = viewModel.stateFlow.value
val updatedPasswordOptions = PasswordGenerationOptions(
val updatedPasswordOptions = PasscodeGenerationOptions(
length = 14,
allowAmbiguousChar = false,
hasNumbers = true,
@ -59,6 +59,10 @@ class GeneratorViewModelTest : BaseViewModelTest() {
minLowercase = null,
allowSpecial = false,
minSpecial = 1,
allowCapitalize = false,
allowIncludeNumber = false,
wordSeparator = "-",
numWords = 3,
)
fakeGeneratorRepository.setMockGeneratePasswordResult(
@ -72,7 +76,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
assertEquals(
updatedPasswordOptions,
fakeGeneratorRepository.getPasswordGenerationOptions(),
fakeGeneratorRepository.getPasscodeGenerationOptions(),
)
}