328 lines
11 KiB
Kotlin
328 lines
11 KiB
Kotlin
package at.mocode.ui.viewmodel
|
|
|
|
import at.mocode.enums.GeschlechtE
|
|
import at.mocode.members.application.usecase.CreatePersonUseCase
|
|
import at.mocode.members.domain.model.DomPerson
|
|
import at.mocode.members.domain.repository.PersonRepository
|
|
import at.mocode.members.domain.repository.VereinRepository
|
|
import at.mocode.members.domain.service.MasterDataService
|
|
import com.benasher44.uuid.uuid4
|
|
import kotlinx.coroutines.Dispatchers
|
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
import kotlinx.coroutines.test.*
|
|
import kotlin.test.*
|
|
|
|
@OptIn(ExperimentalCoroutinesApi::class)
|
|
class CreatePersonViewModelTest {
|
|
|
|
private lateinit var mockPersonRepository: PersonRepository
|
|
private lateinit var mockVereinRepository: VereinRepository
|
|
private lateinit var mockMasterDataService: MasterDataService
|
|
private lateinit var createPersonUseCase: CreatePersonUseCase
|
|
private lateinit var viewModel: CreatePersonViewModel
|
|
private val testDispatcher = StandardTestDispatcher()
|
|
|
|
@BeforeTest
|
|
fun setup() {
|
|
Dispatchers.setMain(testDispatcher)
|
|
|
|
mockPersonRepository = object : PersonRepository {
|
|
private val persons = mutableListOf<DomPerson>()
|
|
|
|
override suspend fun save(person: DomPerson): DomPerson {
|
|
val savedPerson = person.copy(personId = uuid4())
|
|
persons.add(savedPerson)
|
|
return savedPerson
|
|
}
|
|
|
|
override suspend fun findById(id: com.benasher44.uuid.Uuid): DomPerson? {
|
|
return persons.find { it.personId == id }
|
|
}
|
|
|
|
override suspend fun findByOepsSatzNr(oepsSatzNr: String): DomPerson? {
|
|
return persons.find { it.oepsSatzNr == oepsSatzNr }
|
|
}
|
|
|
|
override suspend fun findByStammVereinId(vereinId: com.benasher44.uuid.Uuid): List<DomPerson> {
|
|
return persons.filter { it.stammVereinId == vereinId }
|
|
}
|
|
|
|
override suspend fun findByName(searchTerm: String, limit: Int): List<DomPerson> {
|
|
return persons.filter {
|
|
it.vorname.contains(searchTerm, ignoreCase = true) ||
|
|
it.nachname.contains(searchTerm, ignoreCase = true)
|
|
}.take(limit)
|
|
}
|
|
|
|
override suspend fun findAllActive(limit: Int, offset: Int): List<DomPerson> {
|
|
return persons.filter { !it.istGesperrt }.drop(offset).take(limit)
|
|
}
|
|
|
|
override suspend fun existsByOepsSatzNr(oepsSatzNr: String): Boolean {
|
|
return persons.any { it.oepsSatzNr == oepsSatzNr }
|
|
}
|
|
|
|
override suspend fun countActive(): Long {
|
|
return persons.count { !it.istGesperrt }.toLong()
|
|
}
|
|
|
|
override suspend fun delete(id: com.benasher44.uuid.Uuid): Boolean {
|
|
return persons.removeAll { it.personId == id }
|
|
}
|
|
}
|
|
|
|
mockVereinRepository = object : VereinRepository {
|
|
override suspend fun findById(id: com.benasher44.uuid.Uuid): at.mocode.members.domain.model.DomVerein? {
|
|
return null
|
|
}
|
|
|
|
override suspend fun findByOepsVereinsNr(oepsVereinsNr: String): at.mocode.members.domain.model.DomVerein? {
|
|
return null
|
|
}
|
|
|
|
override suspend fun findByName(searchTerm: String, limit: Int): List<at.mocode.members.domain.model.DomVerein> {
|
|
return emptyList()
|
|
}
|
|
|
|
override suspend fun findByBundeslandId(bundeslandId: com.benasher44.uuid.Uuid): List<at.mocode.members.domain.model.DomVerein> {
|
|
return emptyList()
|
|
}
|
|
|
|
override suspend fun findByLandId(landId: com.benasher44.uuid.Uuid): List<at.mocode.members.domain.model.DomVerein> {
|
|
return emptyList()
|
|
}
|
|
|
|
override suspend fun findAllActive(limit: Int, offset: Int): List<at.mocode.members.domain.model.DomVerein> {
|
|
return emptyList()
|
|
}
|
|
|
|
override suspend fun findByLocation(searchTerm: String, limit: Int): List<at.mocode.members.domain.model.DomVerein> {
|
|
return emptyList()
|
|
}
|
|
|
|
override suspend fun save(verein: at.mocode.members.domain.model.DomVerein): at.mocode.members.domain.model.DomVerein {
|
|
return verein
|
|
}
|
|
|
|
override suspend fun delete(id: com.benasher44.uuid.Uuid): Boolean {
|
|
return true
|
|
}
|
|
|
|
override suspend fun existsByOepsVereinsNr(oepsVereinsNr: String): Boolean {
|
|
return false
|
|
}
|
|
|
|
override suspend fun countActive(): Long {
|
|
return 0L
|
|
}
|
|
|
|
override suspend fun countActiveByBundeslandId(bundeslandId: com.benasher44.uuid.Uuid): Long {
|
|
return 0L
|
|
}
|
|
}
|
|
|
|
mockMasterDataService = object : MasterDataService {
|
|
override suspend fun countryExists(countryId: com.benasher44.uuid.Uuid): Boolean {
|
|
return true
|
|
}
|
|
|
|
override suspend fun stateExists(stateId: com.benasher44.uuid.Uuid): Boolean {
|
|
return true
|
|
}
|
|
|
|
override suspend fun getCountryById(countryId: com.benasher44.uuid.Uuid): MasterDataService.CountryInfo? {
|
|
return null
|
|
}
|
|
|
|
override suspend fun getStateById(stateId: com.benasher44.uuid.Uuid): MasterDataService.StateInfo? {
|
|
return null
|
|
}
|
|
|
|
override suspend fun getAllCountries(): List<MasterDataService.CountryInfo> {
|
|
return emptyList()
|
|
}
|
|
|
|
override suspend fun getStatesByCountry(countryId: com.benasher44.uuid.Uuid): List<MasterDataService.StateInfo> {
|
|
return emptyList()
|
|
}
|
|
}
|
|
|
|
createPersonUseCase = CreatePersonUseCase(
|
|
personRepository = mockPersonRepository,
|
|
vereinRepository = mockVereinRepository,
|
|
masterDataService = mockMasterDataService
|
|
)
|
|
|
|
viewModel = CreatePersonViewModel(createPersonUseCase)
|
|
}
|
|
|
|
@AfterTest
|
|
fun tearDown() {
|
|
Dispatchers.resetMain()
|
|
}
|
|
|
|
@Test
|
|
fun `initial state should be correct`() {
|
|
assertEquals("", viewModel.nachname)
|
|
assertEquals("", viewModel.vorname)
|
|
assertEquals("", viewModel.titel)
|
|
assertEquals("", viewModel.oepsSatzNr)
|
|
assertEquals("", viewModel.geburtsdatum)
|
|
assertNull(viewModel.geschlecht)
|
|
assertEquals("", viewModel.telefon)
|
|
assertEquals("", viewModel.email)
|
|
assertEquals("", viewModel.strasse)
|
|
assertEquals("", viewModel.plz)
|
|
assertEquals("", viewModel.ort)
|
|
assertEquals("", viewModel.adresszusatz)
|
|
assertEquals("", viewModel.feiId)
|
|
assertEquals("", viewModel.mitgliedsNummer)
|
|
assertEquals("", viewModel.notizen)
|
|
assertFalse(viewModel.istGesperrt)
|
|
assertEquals("", viewModel.sperrGrund)
|
|
assertFalse(viewModel.isLoading)
|
|
assertNull(viewModel.errorMessage)
|
|
assertFalse(viewModel.isSuccess)
|
|
}
|
|
|
|
@Test
|
|
fun `update methods should change state correctly`() {
|
|
viewModel.updateNachname("Mustermann")
|
|
viewModel.updateVorname("Max")
|
|
viewModel.updateTitel("Dr.")
|
|
viewModel.updateGeschlecht(GeschlechtE.M)
|
|
viewModel.updateEmail("max@example.com")
|
|
viewModel.updateIstGesperrt(true)
|
|
|
|
assertEquals("Mustermann", viewModel.nachname)
|
|
assertEquals("Max", viewModel.vorname)
|
|
assertEquals("Dr.", viewModel.titel)
|
|
assertEquals(GeschlechtE.M, viewModel.geschlecht)
|
|
assertEquals("max@example.com", viewModel.email)
|
|
assertTrue(viewModel.istGesperrt)
|
|
}
|
|
|
|
@Test
|
|
fun `createPerson should fail with empty nachname`() = runTest {
|
|
// Given - empty nachname
|
|
viewModel.updateVorname("Max")
|
|
|
|
// When
|
|
viewModel.createPerson()
|
|
testDispatcher.scheduler.advanceUntilIdle()
|
|
|
|
// Then
|
|
assertEquals("Nachname ist erforderlich", viewModel.errorMessage)
|
|
assertFalse(viewModel.isSuccess)
|
|
assertFalse(viewModel.isLoading)
|
|
}
|
|
|
|
@Test
|
|
fun `createPerson should fail with empty vorname`() = runTest {
|
|
// Given - empty vorname
|
|
viewModel.updateNachname("Mustermann")
|
|
|
|
// When
|
|
viewModel.createPerson()
|
|
testDispatcher.scheduler.advanceUntilIdle()
|
|
|
|
// Then
|
|
assertEquals("Vorname ist erforderlich", viewModel.errorMessage)
|
|
assertFalse(viewModel.isSuccess)
|
|
assertFalse(viewModel.isLoading)
|
|
}
|
|
|
|
@Test
|
|
fun `createPerson should succeed with valid data`() = runTest {
|
|
// Given
|
|
viewModel.updateNachname("Mustermann")
|
|
viewModel.updateVorname("Max")
|
|
viewModel.updateGeschlecht(GeschlechtE.M)
|
|
viewModel.updateEmail("max@example.com")
|
|
|
|
// When
|
|
viewModel.createPerson()
|
|
testDispatcher.scheduler.advanceUntilIdle()
|
|
|
|
// Then
|
|
assertTrue(viewModel.isSuccess)
|
|
assertNull(viewModel.errorMessage)
|
|
assertFalse(viewModel.isLoading)
|
|
}
|
|
|
|
@Test
|
|
fun `createPerson should handle invalid date format`() = runTest {
|
|
// Given
|
|
viewModel.updateNachname("Mustermann")
|
|
viewModel.updateVorname("Max")
|
|
viewModel.updateGeburtsdatum("invalid-date")
|
|
|
|
// When
|
|
viewModel.createPerson()
|
|
testDispatcher.scheduler.advanceUntilIdle()
|
|
|
|
// Then
|
|
assertEquals("Ungültiges Datumsformat. Verwenden Sie YYYY-MM-DD", viewModel.errorMessage)
|
|
assertFalse(viewModel.isSuccess)
|
|
assertFalse(viewModel.isLoading)
|
|
}
|
|
|
|
@Test
|
|
fun `createPerson should handle valid date format`() = runTest {
|
|
// Given
|
|
viewModel.updateNachname("Mustermann")
|
|
viewModel.updateVorname("Max")
|
|
viewModel.updateGeburtsdatum("1990-05-15")
|
|
|
|
// When
|
|
viewModel.createPerson()
|
|
testDispatcher.scheduler.advanceUntilIdle()
|
|
|
|
// Then
|
|
assertTrue(viewModel.isSuccess)
|
|
assertNull(viewModel.errorMessage)
|
|
assertFalse(viewModel.isLoading)
|
|
}
|
|
|
|
@Test
|
|
fun `resetForm should clear all fields`() {
|
|
// Given - set some values
|
|
viewModel.updateNachname("Mustermann")
|
|
viewModel.updateVorname("Max")
|
|
viewModel.updateEmail("max@example.com")
|
|
viewModel.updateIstGesperrt(true)
|
|
|
|
// When
|
|
viewModel.resetForm()
|
|
|
|
// Then
|
|
assertEquals("", viewModel.nachname)
|
|
assertEquals("", viewModel.vorname)
|
|
assertEquals("", viewModel.email)
|
|
assertFalse(viewModel.istGesperrt)
|
|
assertFalse(viewModel.isLoading)
|
|
assertNull(viewModel.errorMessage)
|
|
assertFalse(viewModel.isSuccess)
|
|
}
|
|
|
|
@Test
|
|
fun `clearError should reset error message`() = runTest {
|
|
// Given - simulate an error
|
|
viewModel.updateNachname("") // This will cause validation error
|
|
viewModel.updateVorname("Max")
|
|
|
|
// When
|
|
viewModel.createPerson()
|
|
testDispatcher.scheduler.advanceUntilIdle()
|
|
|
|
// Then - verify error message exists
|
|
assertNotNull(viewModel.errorMessage)
|
|
|
|
// When - clear the error
|
|
viewModel.clearError()
|
|
|
|
// Then - verify error message is cleared
|
|
assertNull(viewModel.errorMessage)
|
|
}
|
|
}
|