Coverage Summary for Class: TransactionAmountError (com.georgeci.moneysurfer.feature.transaction.creation)
| Class |
Class, %
|
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| TransactionAmountError |
100%
(1/1)
|
100%
(1/1)
|
|
100%
(1/1)
|
100%
(18/18)
|
package com.georgeci.moneysurfer.feature.transaction.creation
/**
* Pure validation for the transaction amount fields (single amount and both
* transfer legs). Lives outside the ViewModel so the parsing rules can be
* unit-tested directly — same split as `InitialBalanceInput` in feature/account.
*/
object TransactionAmountInput {
/** Digits with at most one decimal separator; no sign, no exponent. */
private val AMOUNT_PATTERN = Regex("""\d*\.?\d*""")
/**
* Parses a raw amount (',' normalised to '.') to a [Double], or null when
* the text is not a plain unsigned decimal — e.g. "1.2.3", "12a", "-5".
*/
fun parse(amount: String): Double? {
val normalized = amount.replace(',', '.')
if (!normalized.matches(AMOUNT_PATTERN)) return null
return normalized.toDoubleOrNull()
}
/** Submit gate: the amount parses and is strictly positive. */
fun isValid(amount: String): Boolean = (parse(amount) ?: return false) > 0.0
/**
* The inline error to surface for [amount], or null when the field is
* empty (nothing to complain about yet) or holds a positive amount.
*/
fun errorFor(amount: String): TransactionAmountError? {
if (amount.isBlank()) return null
val parsed = parse(amount) ?: return TransactionAmountError.INVALID_FORMAT
return if (parsed > 0.0) null else TransactionAmountError.NOT_POSITIVE
}
}
/** Validation failures for a transaction amount field. */
enum class TransactionAmountError { INVALID_FORMAT, NOT_POSITIVE }