Coverage Summary for Class: AmountInputTransformation (com.georgeci.moneysurfer.utils)

Class Class, % Method, % Branch, % Line, % Instruction, %
AmountInputTransformation 100% (1/1) 100% (3/3) 100% (18/18) 100% (14/14) 100% (114/114)


 package com.georgeci.moneysurfer.utils
 
 import androidx.compose.foundation.text.input.InputTransformation
 import androidx.compose.foundation.text.input.TextFieldBuffer
 
 object AmountInputTransformation : InputTransformation {
 
     override fun TextFieldBuffer.transformInput() {
         val text = asCharSequence().toString()
 
         if (text.isEmpty()) return
 
         val result = validateAndNormalize(text)
         if (result == null) {
             revertAllChanges()
             return
         }
 
         if (result != text) {
             replace(0, length, result)
         }
     }
 
     /**
      * Validates and normalizes amount input.
      * Returns the normalized string if valid, or null if the input should be rejected.
      *
      * Rules:
      * - Only digits and one decimal separator (`.` or `,`) allowed
      * - Comma is normalized to dot
      * - No leading zeros (e.g. "007"), except bare "0" or "0."
      * - Maximum 2 digits after the decimal point
      */
     private val AMOUNT_PATTERN = Regex("^\\d*\\.?\\d*$")
     private const val MAX_DECIMAL_DIGITS = 2
 
     fun validateAndNormalize(input: String): String? {
         val normalized = input.replace(',', '.')
         val parts = normalized.split('.')
         val hasInvalidFormat = !normalized.matches(AMOUNT_PATTERN)
         val hasLeadingZeros = parts[0].length > 1 && parts[0].startsWith('0')
         val hasTooManyDecimals = parts.size == 2 && parts[1].length > MAX_DECIMAL_DIGITS
 
         return normalized.takeUnless { hasInvalidFormat || hasLeadingZeros || hasTooManyDecimals }
     }
 }