Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ dependencies {
testImplementation(libs.junit)
testImplementation(libs.mockito.kotlin)
testImplementation(libs.kotlinx.coroutines.test)
testImplementation(libs.androidx.arch.core.testing)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
androidTestImplementation(platform(libs.androidx.compose.bom))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
@file:Suppress("PackageName")

package ee.ria.DigiDoc.viewmodel

import android.content.Context
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.lifecycle.Observer
import androidx.test.platform.app.InstrumentationRegistry
import ee.ria.DigiDoc.R
import ee.ria.DigiDoc.configuration.repository.ConfigurationRepository
import ee.ria.DigiDoc.cryptolib.Addressee
import ee.ria.DigiDoc.cryptolib.CDOC2Settings
import ee.ria.DigiDoc.cryptolib.CertType
import ee.ria.DigiDoc.cryptolib.CryptoContainer
import ee.ria.DigiDoc.cryptolib.exception.CryptoException
import ee.ria.DigiDoc.cryptolib.repository.RecipientRepository
import ee.ria.DigiDoc.utilsLib.mimetype.MimeTypeResolver
import ee.ria.DigiDoc.viewmodel.shared.SharedContainerViewModel
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Assert.fail
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.MockitoAnnotations
import org.mockito.junit.MockitoJUnitRunner
import java.io.File

@RunWith(MockitoJUnitRunner::class)
class EncryptRecipientViewModelTest {
@get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule()

@Mock
private lateinit var mimeTypeResolver: MimeTypeResolver

@Mock
private lateinit var recipientRepository: RecipientRepository

@Mock
private lateinit var configurationRepository: ConfigurationRepository

@Mock
private lateinit var errorStateObserver: Observer<Int?>

private lateinit var context: Context
private lateinit var sharedContainerViewModel: SharedContainerViewModel
private lateinit var viewModel: EncryptRecipientViewModel

@Before
fun setUp() {
MockitoAnnotations.openMocks(this)
context = InstrumentationRegistry.getInstrumentation().targetContext
sharedContainerViewModel = SharedContainerViewModel(context, context.contentResolver)
viewModel =
EncryptRecipientViewModel(
context,
mimeTypeResolver,
recipientRepository,
CDOC2Settings(context, configurationRepository),
configurationRepository,
)
}

@Test
fun encryptRecipientViewModel_encryptContainerWithPassword_returnsEncryptErrorWithNoContainer() =
runTest {
viewModel.errorState.observeForever(errorStateObserver)

viewModel.encryptContainerWithPassword("MyKey", "password123".toByteArray(), sharedContainerViewModel)

assertEquals(R.string.crypto_encrypt_error, viewModel.errorState.value)
}

@Test
fun encryptRecipientViewModel_decryptContainerWithPassword_throwsCryptoExceptionWithNoContainer() =
runTest {
try {
viewModel.decryptContainerWithPassword("password123".toByteArray(), sharedContainerViewModel)
fail("Expected CryptoException to be thrown")
} catch (e: CryptoException) {
assertEquals("No container to decrypt", e.message)
}
}

@Test
fun encryptRecipientViewModel_resetErrorState_clearsErrorState() =
runTest {
viewModel.encryptContainerWithPassword("key", "pass".toByteArray(), sharedContainerViewModel)
viewModel.resetErrorState()

assertNull(viewModel.errorState.value)
}

@Test
fun encryptRecipientViewModel_encryptContainerWithPassword_returnsDataFilesEmptyErrorWithEmptyDataFiles() =
runTest {
sharedContainerViewModel.setCryptoContainer(
CryptoContainer(
context = context,
file = File(context.cacheDir, "test.cdoc"),
dataFiles = ArrayList(),
recipients =
ArrayList<Addressee>().apply {
add(
Addressee(
data = ByteArray(0),
identifier = "key",
serialNumber = null,
givenName = null,
surname = null,
certType = CertType.PasswordType,
validTo = null,
concatKDFAlgorithmURI = null,
),
)
},
decrypted = false,
encrypted = false,
),
)

viewModel.encryptContainerWithPassword("key", "password".toByteArray(), sharedContainerViewModel)

assertEquals(R.string.crypto_encrypt_data_files_empty_error, viewModel.errorState.value)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.sendAccess
import ee.ria.DigiDoc.utils.extensions.reachedBottom
import ee.ria.DigiDoc.utils.snackbar.SnackBarManager.showMessage
import ee.ria.DigiDoc.utils.snackbar.SnackbarType
import ee.ria.DigiDoc.utilsLib.logging.LoggingUtil.Companion.debugLog
import ee.ria.DigiDoc.utilsLib.validator.PersonalCodeValidator
import ee.ria.DigiDoc.viewmodel.EncryptRecipientViewModel
import ee.ria.DigiDoc.viewmodel.EncryptViewModel
Expand All @@ -127,6 +128,7 @@ fun EncryptRecipientScreen(
sharedRecipientViewModel: SharedRecipientViewModel,
encryptRecipientViewModel: EncryptRecipientViewModel = hiltViewModel(),
) {
val logTag = "EncryptRecipientScreen"
val context = LocalContext.current

val scope = rememberCoroutineScope()
Expand Down Expand Up @@ -326,6 +328,33 @@ fun EncryptRecipientScreen(
isBottomSheetVisible = isSettingsMenuBottomSheetVisible,
)

@Composable
fun RecipientTab(tabModifier: Modifier) {
RecipientTabContent(
modifier = tabModifier,
expanded = expanded,
onExpandedChange = { expanded = it },
searchText = searchText,
onSearchTextChange = encryptRecipientViewModel::onSearchTextChange,
invalidPersonalCodeMessage = invalidPersonalCodeMessage,
onSearch = { encryptRecipientViewModel.onQueryTextChange(it) },
onDismissSearch = dismissSearch,
recipientList = recipientList,
hasSearched = hasSearched,
containerRecipientList = containerRecipientList.value,
onAddRecipientToContainer = { recipient ->
encryptRecipientViewModel.addRecipientToContainer(
recipient,
sharedContainerViewModel,
)
},
onRecipientClick = { recipient ->
clickedRecipient.value = recipient
showRecipientBottomSheet.value = true
},
)
}

if (isCdoc2) {
Column(
modifier = modifier.padding(paddingValues).fillMaxSize(),
Expand All @@ -341,29 +370,7 @@ fun EncryptRecipientScreen(
tabItems =
listOf(
Pair(tabRecipientTitle) {
RecipientTabContent(
modifier = Modifier.fillMaxSize(),
expanded = expanded,
onExpandedChange = { expanded = it },
searchText = searchText,
onSearchTextChange = encryptRecipientViewModel::onSearchTextChange,
invalidPersonalCodeMessage = invalidPersonalCodeMessage,
onSearch = { encryptRecipientViewModel.onQueryTextChange(it) },
onDismissSearch = dismissSearch,
recipientList = recipientList,
hasSearched = hasSearched,
containerRecipientList = containerRecipientList.value,
onAddRecipientToContainer = { recipient ->
encryptRecipientViewModel.addRecipientToContainer(
recipient,
sharedContainerViewModel,
)
},
onRecipientClick = { recipient ->
clickedRecipient.value = recipient
showRecipientBottomSheet.value = true
},
)
RecipientTab(Modifier.fillMaxSize())
},
Pair(tabPasswordTitle) {
PasswordTabContent(modifier = Modifier.fillMaxSize())
Expand All @@ -372,36 +379,27 @@ fun EncryptRecipientScreen(
)
}
} else {
RecipientTabContent(
modifier = Modifier.padding(paddingValues).fillMaxWidth(),
expanded = expanded,
onExpandedChange = { expanded = it },
searchText = searchText,
onSearchTextChange = encryptRecipientViewModel::onSearchTextChange,
invalidPersonalCodeMessage = invalidPersonalCodeMessage,
onSearch = { encryptRecipientViewModel.onQueryTextChange(it) },
onDismissSearch = dismissSearch,
recipientList = recipientList,
hasSearched = hasSearched,
containerRecipientList = containerRecipientList.value,
onAddRecipientToContainer = { recipient ->
encryptRecipientViewModel.addRecipientToContainer(
recipient,
sharedContainerViewModel,
)
},
onRecipientClick = { recipient ->
clickedRecipient.value = recipient
showRecipientBottomSheet.value = true
},
)
RecipientTab(Modifier.padding(paddingValues).fillMaxWidth())
}

if (showPasswordDialog.value) {
EncryptPasswordDialog(
modifier = modifier,
onDismiss = { showPasswordDialog.value = false },
onEncrypt = { _, _ -> showPasswordDialog.value = false },
onEncrypt = { keyLabel, password ->
debugLog(logTag, "User submitted password encryption dialog")
showPasswordDialog.value = false
encryptionButtonEnabled.value = false
showLoading.value = true
scope.launch(Main) {
encryptRecipientViewModel.encryptContainerWithPassword(
keyLabel = keyLabel,
password = password.toByteArray(Charsets.UTF_8),
sharedContainerViewModel = sharedContainerViewModel,
)
showLoading.value = false
}
},
)
}

Expand Down
Loading
Loading