From dccb4f8cdac9d5869168b5a3eda290ae37817b03 Mon Sep 17 00:00:00 2001 From: = Date: Mon, 25 May 2026 15:14:15 +0200 Subject: [PATCH] Feat: Refactored transactionarchive + testing Replaced for loops with streams, centralized concrete getters via get transactions, and added parameter guarding. Also updated test class. --- .../g40/mappe/engine/TransactionArchive.java | 78 ++++--- .../mappe/engine/TransactionArchiveTest.java | 202 +++++++++++------- 2 files changed, 162 insertions(+), 118 deletions(-) diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/TransactionArchive.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/TransactionArchive.java index dadc496..b7b9cf5 100644 --- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/TransactionArchive.java +++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/TransactionArchive.java @@ -3,11 +3,15 @@ import edu.ntnu.idi.idatt2003.g40.mappe.model.Purchase; import edu.ntnu.idi.idatt2003.g40.mappe.model.Sale; import edu.ntnu.idi.idatt2003.g40.mappe.model.Transaction; +import edu.ntnu.idi.idatt2003.g40.mappe.utils.Validator; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** - * Stores completed transactions. + * Stores completed transactions in an {@link ArrayList} object. + * + * @version 1.1.0 */ public final class TransactionArchive { @@ -20,6 +24,7 @@ public final class TransactionArchive { * Creates an empty transaction archive. */ public TransactionArchive() { + // Empty constructor. } /** @@ -28,8 +33,13 @@ public TransactionArchive() { * @param transaction the transaction to add * * @return true if the transaction was added + * + * @throws IllegalArgumentException if transaction is null */ public boolean add(final Transaction transaction) { + if (transaction == null) { + throw new IllegalArgumentException("Transaction cannot be null!"); + } return transactions.add(transaction); } @@ -48,24 +58,27 @@ public boolean isEmpty() { * @param week the week number * * @return list of transactions from the given week + * + * @throws IllegalArgumentException if week is less than 1. */ public List getTransactions(final int week) { - List result = new ArrayList<>(); - for (Transaction transaction : transactions) { - if (transaction.getWeek() == week) { - result.add(transaction); - } + if (!Validator.VALID_WEEK.isValid(Integer.toString(week))) { + throw new IllegalArgumentException( + Validator.VALID_WEEK.getErrorMessage() + ); } - return result; + return transactions.stream() + .filter(transaction -> transaction.getWeek() == week) + .toList(); } /** - * Returns all transactions. + * Returns an un-mutable reference to the transactions list. * - * @return list of transactions from the given week + * @return unmodifiable version of list. */ public List getTransactions() { - return transactions; + return Collections.unmodifiableList(transactions); } /** @@ -74,16 +87,15 @@ public List getTransactions() { * @param week the week number * * @return list of purchases from the given week + * + * @throws IllegalArgumentException if week is less than 1. */ - public List getPurchases(final int week) { - List result = new ArrayList<>(); - for (Transaction transaction : transactions) { - if (transaction instanceof Purchase purchase - && transaction.getWeek() == week) { - result.add(purchase); - } - } - return result; + public List getPurchases(final int week) + throws IllegalArgumentException { + return getTransactions(week).stream() + .filter(Purchase.class::isInstance) + .map(Purchase.class::cast) + .toList(); } /** @@ -92,15 +104,15 @@ public List getPurchases(final int week) { * @param week the week number * * @return list of sales from the given week + * + * @throws IllegalArgumentException if week is less than 1. */ - public List getSales(final int week) { - List result = new ArrayList<>(); - for (Transaction transaction : transactions) { - if (transaction instanceof Sale sale && transaction.getWeek() == week) { - result.add(sale); - } - } - return result; + public List getSales(final int week) + throws IllegalArgumentException { + return getTransactions(week).stream() + .filter(Sale.class::isInstance) + .map(Sale.class::cast) + .toList(); } /** @@ -109,13 +121,9 @@ public List getSales(final int week) { * @return number of distinct weeks */ public int countDistinctWeeks() { - List weeks = new ArrayList<>(); - for (Transaction transaction : transactions) { - int week = transaction.getWeek(); - if (!weeks.contains(week)) { - weeks.add(week); - } - } - return weeks.size(); + return (int) transactions.stream() + .map(Transaction::getWeek) + .distinct() + .count(); } } diff --git a/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/TransactionArchiveTest.java b/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/TransactionArchiveTest.java index 091daeb..78ffaf7 100644 --- a/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/TransactionArchiveTest.java +++ b/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/TransactionArchiveTest.java @@ -1,141 +1,177 @@ package edu.ntnu.idi.idatt2003.g40.mappe.engine; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import edu.ntnu.idi.idatt2003.g40.mappe.model.Purchase; +import edu.ntnu.idi.idatt2003.g40.mappe.model.Sale; +import edu.ntnu.idi.idatt2003.g40.mappe.model.Share; +import edu.ntnu.idi.idatt2003.g40.mappe.model.Stock; +import edu.ntnu.idi.idatt2003.g40.mappe.model.Transaction; +import edu.ntnu.idi.idatt2003.g40.mappe.service.PurchaseCalculator; +import edu.ntnu.idi.idatt2003.g40.mappe.service.SaleCalculator; +import edu.ntnu.idi.idatt2003.g40.mappe.service.TransactionFactory; +import edu.ntnu.idi.idatt2003.g40.mappe.service.TransactionType; import java.math.BigDecimal; import java.util.List; - -import edu.ntnu.idi.idatt2003.g40.mappe.model.*; -import edu.ntnu.idi.idatt2003.g40.mappe.service.TransactionCalculator; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; final class TransactionArchiveTest { /** - * Transaction calculator to be used for testing. + * Test transactionArchive. + * */ + private TransactionArchive transactionArchive; + + /** + * Sample share used to emulate transactions. + * */ + private Share sampleShare; + + /** + * Sample sale calculator to calculate sales. + * */ + private SaleCalculator saleCalculator; + + /** + * Sample purchase calculater used to calculate purchases. * */ - private final TransactionCalculator calculator = new TransactionCalculator() { - @Override - public BigDecimal calculateGross() { - return BigDecimal.ZERO; - } - - @Override - public BigDecimal calculateCommission() { - return BigDecimal.ZERO; - } - - @Override - public BigDecimal calculateTax() { - return BigDecimal.ZERO; - } - - @Override - public BigDecimal calculateTotal() { - return BigDecimal.ZERO; - } - }; + private PurchaseCalculator purchaseCalculator; + + @BeforeEach + void setUp() { + transactionArchive = new TransactionArchive(); + Stock sampleStock = new Stock("AAPL", "Apple", new BigDecimal("100.00")); + sampleShare = new Share(sampleStock, + new BigDecimal("1.00"), sampleStock.getSalesPrice()); + saleCalculator = new SaleCalculator(sampleShare); + purchaseCalculator = new PurchaseCalculator(sampleShare); + } @Test void newArchiveIsEmpty() { - TransactionArchive archive = new TransactionArchive(); - - assertTrue(archive.isEmpty()); + assertTrue(transactionArchive.isEmpty()); } @Test - void addMakesArchiveNonEmpty() { - TransactionArchive archive = new TransactionArchive(); - Transaction transaction = createPurchase("AAPL", "Apple", 1); + void addValidTransactionMakesArchiveNonEmpty() { + Transaction purchase = createPurchase(1); - boolean result = archive.add(transaction); + boolean result = transactionArchive.add(purchase); assertTrue(result); - assertFalse(archive.isEmpty()); + assertFalse(transactionArchive.isEmpty()); } @Test - void getTransactionsReturnsOnlyTransactionsFromGivenWeek() { - TransactionArchive archive = new TransactionArchive(); + void addNullTransactionThrowsException() { + Transaction purchase = createPurchase(1); + assertDoesNotThrow(() -> transactionArchive.add(purchase)); + assertThrows(IllegalArgumentException.class, + () -> transactionArchive.add(null)); + } + + @Test + void genericGetTransactionsGetsAllTransactions() { + Transaction week1Purchase1 = createPurchase(1); + Transaction week1Purchase2 = createPurchase(1); + Transaction week2Purchase = createPurchase(2); + Transaction week4Sale = createPurchase(4); + + transactionArchive.add(week1Purchase1); + transactionArchive.add(week1Purchase2); + transactionArchive.add(week2Purchase); + transactionArchive.add(week4Sale); + + List result = transactionArchive.getTransactions(); + + assertEquals(4, result.size()); + assertTrue(result.contains(week1Purchase1)); + assertTrue(result.contains(week1Purchase2)); + assertTrue(result.contains(week2Purchase)); + assertTrue(result.contains(week4Sale)); + } - Transaction transaction1 = createPurchase("AAPL", "Apple", 1); - Transaction transaction2 = createSale("TSLA", "Tesla", 2); - Transaction transaction3 = createPurchase("NVDA", "Nvidia", 1); + @Test + void getTransactionsWithWeekSpecifierReturnsOnlyTransactionsFromGivenWeek() { + Transaction week1Purchase1 = createPurchase(1); + Transaction week1Purchase2 = createPurchase(1); + Transaction week2Purchase = createPurchase(2); - archive.add(transaction1); - archive.add(transaction2); - archive.add(transaction3); + transactionArchive.add(week1Purchase1); + transactionArchive.add(week1Purchase2); + transactionArchive.add(week2Purchase); - List result = archive.getTransactions(1); + List result = transactionArchive.getTransactions(1); assertEquals(2, result.size()); - assertTrue(result.contains(transaction1)); - assertTrue(result.contains(transaction3)); + assertTrue(result.contains(week1Purchase1)); + assertTrue(result.contains(week1Purchase2)); + assertFalse(result.contains(week2Purchase)); } @Test - void getPurchasesReturnsOnlyPurchasesFromGivenWeek() { - TransactionArchive archive = new TransactionArchive(); + void getTransactionsWithWeekSpecifierInvalidWeekThrowsException() { + assertDoesNotThrow(() -> transactionArchive.getTransactions(1)); + assertThrows(IllegalArgumentException.class, + () -> transactionArchive.getTransactions(0)); + } - Purchase purchase1 = createPurchase("AAPL", "Apple", 1); - Purchase purchase2 = createPurchase("NVDA", "Nvidia", 2); - Sale sale = createSale("TSLA", "Tesla", 1); + @Test + void getPurchasesReturnsOnlyPurchasesFromGivenWeek() { + Transaction week1Purchase = createPurchase(1); + Transaction week2Purchase = createPurchase(2); + Transaction week1Sale = createSale(1); - archive.add(purchase1); - archive.add(purchase2); - archive.add(sale); + transactionArchive.add(week1Purchase); + transactionArchive.add(week2Purchase); + transactionArchive.add(week1Sale); - List result = archive.getPurchases(1); + List result = transactionArchive.getPurchases(1); assertEquals(1, result.size()); - assertTrue(result.contains(purchase1)); + assertTrue(result.contains(week1Purchase)); } @Test void getSalesReturnsOnlySalesFromGivenWeek() { - TransactionArchive archive = new TransactionArchive(); + Transaction week1Sale = createSale(1); + Transaction week3Sale = createSale(3); + Transaction week1Purchase = createPurchase(1); - Sale sale1 = createSale("TSLA", "Tesla", 1); - Sale sale2 = createSale("NVDA", "Nvidia", 2); - Purchase purchase = createPurchase("AAPL", "Apple", 1); + transactionArchive.add(week1Sale); + transactionArchive.add(week3Sale); + transactionArchive.add(week1Purchase); - archive.add(sale1); - archive.add(sale2); - archive.add(purchase); - - List result = archive.getSales(1); + List result = transactionArchive.getSales(1); assertEquals(1, result.size()); - assertTrue(result.contains(sale1)); + assertTrue(result.contains(week1Sale)); } @Test void countDistinctWeeksCountsUniqueWeeksOnly() { - TransactionArchive archive = new TransactionArchive(); - - archive.add(createPurchase("AAPL", "Apple", 1)); - archive.add(createSale("TSLA", "Tesla", 1)); - archive.add(createPurchase("NVDA", "Nvidia", 2)); - archive.add(createSale("META", "Meta", 3)); + transactionArchive.add(createPurchase(1)); + transactionArchive.add(createPurchase(1)); + transactionArchive.add(createPurchase(2)); + transactionArchive.add(createSale(3)); - assertEquals(3, archive.countDistinctWeeks()); + assertEquals(3, transactionArchive.countDistinctWeeks()); } - private Purchase createPurchase(final String symbol, - final String company, - final int week) { - Stock stock = new Stock(symbol, company, new BigDecimal("100")); - Share share = new Share(stock, BigDecimal.ONE, new BigDecimal("100")); - return new Purchase(share, week, calculator); + private Transaction createPurchase(int week) { + return TransactionFactory.createTransaction( + TransactionType.PURCHASE, sampleShare, week, purchaseCalculator + ); } - private Sale createSale(final String symbol, - final String company, - final int week) { - Stock stock = new Stock(symbol, company, new BigDecimal("100")); - Share share = new Share(stock, BigDecimal.ONE, new BigDecimal("100")); - return new Sale(share, week, calculator); + private Transaction createSale(int week) { + return TransactionFactory.createTransaction( + TransactionType.SALE, sampleShare, week, saleCalculator + ); } }