diff --git a/pom.xml b/pom.xml index 4b5bbcb..fd79a14 100644 --- a/pom.xml +++ b/pom.xml @@ -57,6 +57,12 @@ 5.10.0 test + + org.junit.jupiter + junit-jupiter-params + 5.10.0 + test + org.junit.jupiter junit-jupiter-engine diff --git a/src/main/java/com/andrewlalis/perfin/data/util/CurrencyUtil.java b/src/main/java/com/andrewlalis/perfin/data/util/CurrencyUtil.java index 010482e..44a1fde 100644 --- a/src/main/java/com/andrewlalis/perfin/data/util/CurrencyUtil.java +++ b/src/main/java/com/andrewlalis/perfin/data/util/CurrencyUtil.java @@ -5,10 +5,12 @@ import com.andrewlalis.perfin.model.MoneyValue; import java.math.BigDecimal; import java.math.RoundingMode; import java.text.NumberFormat; +import java.util.Locale; public class CurrencyUtil { public static String formatMoney(MoneyValue money) { - NumberFormat nf = NumberFormat.getCurrencyInstance(); + // TODO: Use locale-dependent formatting. + NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.US); nf.setCurrency(money.currency()); nf.setMaximumFractionDigits(money.currency().getDefaultFractionDigits()); nf.setMinimumFractionDigits(money.currency().getDefaultFractionDigits()); diff --git a/src/main/java/com/andrewlalis/perfin/model/MoneyValue.java b/src/main/java/com/andrewlalis/perfin/model/MoneyValue.java index 1115bc5..09f9030 100644 --- a/src/main/java/com/andrewlalis/perfin/model/MoneyValue.java +++ b/src/main/java/com/andrewlalis/perfin/model/MoneyValue.java @@ -8,4 +8,8 @@ import java.util.Currency; * @param amount The amount of money. * @param currency The currency of the money. */ -public record MoneyValue(BigDecimal amount, Currency currency) {} +public record MoneyValue(BigDecimal amount, Currency currency) { + public static MoneyValue from(String amountStr, String currencyCode) { + return new MoneyValue(new BigDecimal(amountStr), Currency.getInstance(currencyCode)); + } +} diff --git a/src/main/java/com/andrewlalis/perfin/model/history/AccountHistoryItem.java b/src/main/java/com/andrewlalis/perfin/model/history/AccountHistoryItem.java index 4d1e4e1..565452e 100644 --- a/src/main/java/com/andrewlalis/perfin/model/history/AccountHistoryItem.java +++ b/src/main/java/com/andrewlalis/perfin/model/history/AccountHistoryItem.java @@ -1,5 +1,7 @@ package com.andrewlalis.perfin.model.history; +import com.andrewlalis.perfin.model.IdEntity; + import java.time.LocalDateTime; /** @@ -8,23 +10,18 @@ import java.time.LocalDateTime; * what exactly it means, and could be something like an account entry, balance * record, or modifications to the account's properties. */ -public class AccountHistoryItem { - private final long id; +public class AccountHistoryItem extends IdEntity { private final LocalDateTime timestamp; private final long accountId; private final AccountHistoryItemType type; public AccountHistoryItem(long id, LocalDateTime timestamp, long accountId, AccountHistoryItemType type) { - this.id = id; + super(id); this.timestamp = timestamp; this.accountId = accountId; this.type = type; } - public long getId() { - return id; - } - public LocalDateTime getTimestamp() { return timestamp; } diff --git a/src/main/java/com/andrewlalis/perfin/view/component/AccountHistoryAccountEntryTile.java b/src/main/java/com/andrewlalis/perfin/view/component/AccountHistoryAccountEntryTile.java index 20b01c1..d78d42c 100644 --- a/src/main/java/com/andrewlalis/perfin/view/component/AccountHistoryAccountEntryTile.java +++ b/src/main/java/com/andrewlalis/perfin/view/component/AccountHistoryAccountEntryTile.java @@ -14,7 +14,7 @@ import static com.andrewlalis.perfin.PerfinApp.router; public class AccountHistoryAccountEntryTile extends AccountHistoryItemTile { public AccountHistoryAccountEntryTile(AccountHistoryItem item, AccountHistoryItemRepository repo) { super(item); - AccountEntry entry = repo.getAccountEntryItem(item.getId()); + AccountEntry entry = repo.getAccountEntryItem(item.id); if (entry == null) { setCenter(new TextFlow(new Text("Deleted account entry because of deleted transaction."))); return; diff --git a/src/main/java/com/andrewlalis/perfin/view/component/AccountHistoryBalanceRecordTile.java b/src/main/java/com/andrewlalis/perfin/view/component/AccountHistoryBalanceRecordTile.java index 8d11d31..c9f3c04 100644 --- a/src/main/java/com/andrewlalis/perfin/view/component/AccountHistoryBalanceRecordTile.java +++ b/src/main/java/com/andrewlalis/perfin/view/component/AccountHistoryBalanceRecordTile.java @@ -15,7 +15,7 @@ import javafx.scene.text.TextFlow; public class AccountHistoryBalanceRecordTile extends AccountHistoryItemTile { public AccountHistoryBalanceRecordTile(AccountHistoryItem item, AccountHistoryItemRepository repo, AccountViewController controller) { super(item); - BalanceRecord balanceRecord = repo.getBalanceRecordItem(item.getId()); + BalanceRecord balanceRecord = repo.getBalanceRecordItem(item.id); if (balanceRecord == null) { setCenter(new TextFlow(new Text("Deleted balance record was added."))); return; diff --git a/src/main/java/com/andrewlalis/perfin/view/component/AccountHistoryTextTile.java b/src/main/java/com/andrewlalis/perfin/view/component/AccountHistoryTextTile.java index 1fecb55..22f6c7d 100644 --- a/src/main/java/com/andrewlalis/perfin/view/component/AccountHistoryTextTile.java +++ b/src/main/java/com/andrewlalis/perfin/view/component/AccountHistoryTextTile.java @@ -8,7 +8,7 @@ import javafx.scene.text.TextFlow; public class AccountHistoryTextTile extends AccountHistoryItemTile { public AccountHistoryTextTile(AccountHistoryItem item, AccountHistoryItemRepository repo) { super(item); - String text = repo.getTextItem(item.getId()); + String text = repo.getTextItem(item.id); setCenter(new TextFlow(new Text(text))); } } diff --git a/src/test/java/com/andrewlalis/perfin/data/pagination/PageRequestTest.java b/src/test/java/com/andrewlalis/perfin/data/pagination/PageRequestTest.java new file mode 100644 index 0000000..2b06066 --- /dev/null +++ b/src/test/java/com/andrewlalis/perfin/data/pagination/PageRequestTest.java @@ -0,0 +1,28 @@ +package com.andrewlalis.perfin.data.pagination; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class PageRequestTest { + @Test + public void testToSQL() { + assertEquals("LIMIT 5 OFFSET 0", PageRequest.of(0, 5).toSQL()); + assertEquals("LIMIT 5 OFFSET 5", PageRequest.of(1, 5).toSQL()); + assertEquals("LIMIT 10 OFFSET 0", PageRequest.of(0, 10).toSQL()); + assertEquals("LIMIT 10 OFFSET 20", PageRequest.of(2, 10).toSQL()); + assertEquals("LIMIT 10 OFFSET 30", PageRequest.of(2, 10).next().toSQL()); + assertEquals("LIMIT 10 OFFSET 10", PageRequest.of(2, 10).previous().toSQL()); + assertEquals( + "ORDER BY id DESC LIMIT 5 OFFSET 0", + PageRequest.of(0, 5, Sort.desc("id")).toSQL() + ); + assertEquals( + "ORDER BY timestamp DESC, name ASC LIMIT 10 OFFSET 30", + PageRequest.of(3, 10, Sort.desc("timestamp"), Sort.asc("name")).toSQL() + ); + assertEquals("", PageRequest.unpaged().toSQL()); + assertEquals("ORDER BY id ASC", PageRequest.unpaged(Sort.asc("id")).toSQL()); + + } +} diff --git a/src/test/java/com/andrewlalis/perfin/data/pagination/SortTest.java b/src/test/java/com/andrewlalis/perfin/data/pagination/SortTest.java new file mode 100644 index 0000000..a32ce97 --- /dev/null +++ b/src/test/java/com/andrewlalis/perfin/data/pagination/SortTest.java @@ -0,0 +1,13 @@ +package com.andrewlalis.perfin.data.pagination; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class SortTest { + @Test + public void testToSQL() { + assertEquals("date ASC", Sort.asc("date").toSQL()); + assertEquals("id DESC", Sort.desc("id").toSQL()); + } +} diff --git a/src/test/java/com/andrewlalis/perfin/data/util/CurrencyUtilTest.java b/src/test/java/com/andrewlalis/perfin/data/util/CurrencyUtilTest.java new file mode 100644 index 0000000..a6dc734 --- /dev/null +++ b/src/test/java/com/andrewlalis/perfin/data/util/CurrencyUtilTest.java @@ -0,0 +1,39 @@ +package com.andrewlalis.perfin.data.util; + +import com.andrewlalis.perfin.model.MoneyValue; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class CurrencyUtilTest { + @ParameterizedTest + @MethodSource("testFormatMoneyParams") + public void testFormatMoney(MoneyValue money, String expectedFormat) { + assertEquals(expectedFormat, CurrencyUtil.formatMoney(money)); + } + + static Stream testFormatMoneyParams() { + return Stream.of( + Arguments.of(MoneyValue.from("1.23", "USD"), "$1.23"), + Arguments.of(MoneyValue.from("1000", "USD"), "$1,000.00"), + Arguments.of(MoneyValue.from("10000", "USD"), "$10,000.00"), + Arguments.of(MoneyValue.from("0", "USD"), "$0.00"), + Arguments.of(MoneyValue.from("-4.213", "USD"), "-$4.21"), + Arguments.of(MoneyValue.from("5.6781", "USD"), "$5.68"), + Arguments.of(MoneyValue.from("1.23", "EUR"), "€1.23"), + Arguments.of(MoneyValue.from("212331", "JPY"), "¥212,331") + ); + } + + @Test + public void testFormatMoneyAsBasicNumber() { + assertEquals("1.23", CurrencyUtil.formatMoneyAsBasicNumber(MoneyValue.from("1.23", "USD"))); + assertEquals("5438", CurrencyUtil.formatMoneyAsBasicNumber(MoneyValue.from("5438.213", "JPY"))); + assertEquals("0.00", CurrencyUtil.formatMoneyAsBasicNumber(MoneyValue.from("0", "USD"))); + } +} diff --git a/src/test/java/com/andrewlalis/perfin/model/AccountEntryTest.java b/src/test/java/com/andrewlalis/perfin/model/AccountEntryTest.java new file mode 100644 index 0000000..1310884 --- /dev/null +++ b/src/test/java/com/andrewlalis/perfin/model/AccountEntryTest.java @@ -0,0 +1,37 @@ +package com.andrewlalis.perfin.model; + +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.Currency; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class AccountEntryTest { + @Test + public void testGetEffectiveValue() { + // Debit entry on various accounts. + AccountEntry debitEntry = getMockEntry(new BigDecimal("3.14"), AccountEntry.Type.DEBIT); + assertEquals(new BigDecimal("3.14"), debitEntry.getEffectiveValue(AccountType.CHECKING)); + assertEquals(new BigDecimal("3.14"), debitEntry.getEffectiveValue(AccountType.SAVINGS)); + assertEquals(new BigDecimal("-3.14"), debitEntry.getEffectiveValue(AccountType.CREDIT_CARD)); + + AccountEntry creditEntry = getMockEntry(new BigDecimal("1.23"), AccountEntry.Type.CREDIT); + assertEquals(new BigDecimal("-1.23"), creditEntry.getEffectiveValue(AccountType.CHECKING)); + assertEquals(new BigDecimal("-1.23"), creditEntry.getEffectiveValue(AccountType.SAVINGS)); + assertEquals(new BigDecimal("1.23"), creditEntry.getEffectiveValue(AccountType.CREDIT_CARD)); + } + + private AccountEntry getMockEntry(BigDecimal amount, AccountEntry.Type type) { + return new AccountEntry( + 1, + LocalDateTime.of(2024, 1, 4, 9, 56), + 1, + 1, + amount, + type, + Currency.getInstance("USD") + ); + } +}