Coverage Summary for Class: AccountTotalsKt (com.georgeci.moneysurfer.domain.model)

Class Method, % Branch, % Line, % Instruction, %
AccountTotalsKt 100% (2/2) 100% (13/13) 100% (80/80)
AccountTotalsKt$totalsByCurrency$$inlined$compareByDescending$1 0% (0/1)
AccountTotalsKt$totalsByCurrency$$inlined$thenBy$1 0% (0/1)
Total 50% (2/4) 100% (13/13) 100% (80/80)


 package com.georgeci.moneysurfer.domain.model
 
 import com.georgeci.moneysurfer.domain.formatter.MoneyFormatter
 import com.georgeci.moneysurfer.domain.primitives.CurrencyCode
 import com.georgeci.moneysurfer.domain.primitives.Money
 
 /** Sum of every account balance that shares [currencyCode]. */
 data class CurrencyTotal(
     val currencyCode: CurrencyCode,
     val amount: Money,
 )
 
 /**
  * Balance totals per currency, most-used currency first (ties broken by currency code so the
  * order never depends on how the accounts happen to be sorted).
  *
  * Callers used to sum whatever matched the *first* account's currency and present that as "the"
  * total, which silently dropped every other currency. Adding across currencies is not possible
  * without FX rates, so the honest answer is one figure per currency: the head is the headline,
  * the tail has to be shown somewhere rather than swallowed.
  */
 fun List<Account>.totalsByCurrency(): List<CurrencyTotal> =
     groupBy { it.currencyCode }
         .map { (currency, accounts) ->
             // Carry the bucket size through the sort — it is what "most-used" means, and
             // re-deriving it per comparison would rescan the whole list for every currency.
             CurrencyTotalWithCount(
                 total = CurrencyTotal(
                     currencyCode = currency,
                     amount = accounts.fold(Money.zero()) { acc, account -> acc + account.balance },
                 ),
                 accountCount = accounts.size,
             )
         }
         .sortedWith(
             compareByDescending<CurrencyTotalWithCount> { it.accountCount }
                 .thenBy { it.total.currencyCode.value },
         )
         .map { it.total }
 
 private data class CurrencyTotalWithCount(
     val total: CurrencyTotal,
     val accountCount: Int,
 )
 
 /** [totalsByCurrency] rendered for display, same order — head first, everything else after it. */
 fun List<Account>.formattedTotalsByCurrency(): List<String> =
     totalsByCurrency().map { MoneyFormatter.format(it.amount, it.currencyCode) }