feat(tests): add QA test suites for onboarding and departmental logic validation

- **Onboarding (B-2):** Extracted `OnboardingValidator` and added `OnboardingValidatorTest` for edge-case validations (17 new unit tests: field guards, double-click prevention, cancel/reset behavior, `rememberSaveable` regression fix).
- **Departmental Logic (B-3):** Extended `AbteilungsRegelServiceTest` with 14 new tests covering CSN-C-NEU splitting logic (≤95 cm: license-free/licensed, ≥100 cm: R1/R2+), Caprilli regressions, and organizational/separate award scenarios.
- Updated `AbteilungsRegelService.kt` to implement CSN-C-NEU logic and added `ORGANISATORISCH` + `SEPARATE_SIEGEREHRUNG` enums for new rules.
- Updated Changelog and QA roadmap with completed tasks.

Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
This commit is contained in:
2026-04-03 11:46:00 +02:00
parent 7ff48ed3d7
commit 59f7f8d4ad
8 changed files with 432 additions and 22 deletions
@@ -3,6 +3,7 @@ package at.mocode.desktop.screens.onboarding
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.PasswordVisualTransformation
@@ -20,14 +21,14 @@ fun OnboardingScreen(
onZnsUsb: () -> Unit = {},
onContinue: (geraetName: String, sharedKey: String, znsStatus: ZnsStatus) -> Unit,
) {
var geraetName by remember { mutableStateOf(initialName) }
var sharedKey by remember { mutableStateOf(initialKey) }
var znsStatus by remember { mutableStateOf(initialZns) }
var geraetName by rememberSaveable { mutableStateOf(initialName) }
var sharedKey by rememberSaveable { mutableStateOf(initialKey) }
var znsStatus by rememberSaveable { mutableStateOf(initialZns) }
var showPassword by remember { mutableStateOf(false) }
val nameValid = geraetName.trim().length >= 3
val keyValid = sharedKey.trim().length >= 8
val canContinue = nameValid && keyValid
val nameValid = OnboardingValidator.isNameValid(geraetName)
val keyValid = OnboardingValidator.isKeyValid(sharedKey)
val canContinue = OnboardingValidator.canContinue(geraetName, sharedKey)
Column(
modifier = Modifier.fillMaxSize().padding(24.dp),
@@ -0,0 +1,30 @@
package at.mocode.desktop.screens.onboarding
/**
* Validierungslogik für den Onboarding-Wizard.
*
* Extrahiert aus [OnboardingScreen] für isolierte Unit-Tests (B-2).
* Regeln gemäß Onboarding-Spezifikation:
* - Gerätename: mindestens 3 Zeichen (nach trim)
* - Sicherheitsschlüssel: mindestens 8 Zeichen (nach trim)
*/
object OnboardingValidator {
/** Mindestlänge für den Gerätenamen. */
const val MIN_NAME_LENGTH = 3
/** Mindestlänge für den Sicherheitsschlüssel. */
const val MIN_KEY_LENGTH = 8
/** Gibt `true` zurück, wenn der Gerätename gültig ist. */
fun isNameValid(name: String): Boolean = name.trim().length >= MIN_NAME_LENGTH
/** Gibt `true` zurück, wenn der Sicherheitsschlüssel gültig ist. */
fun isKeyValid(key: String): Boolean = key.trim().length >= MIN_KEY_LENGTH
/**
* Gibt `true` zurück, wenn alle Pflichtfelder gültig sind und
* der „Weiter"-Button aktiviert werden darf.
*/
fun canContinue(name: String, key: String): Boolean = isNameValid(name) && isKeyValid(key)
}