Skip to content

Change into lambda/streams #31

Merged
merged 9 commits into from
May 25, 2026
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 13 additions & 29 deletions src/main/java/Controller/StockFileHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,43 +11,27 @@ public class StockFileHandler {

// lesing
public List<Stock> loadStocksFromFile(String filename) throws IOException {
List<Stock> stocks = new ArrayList<>();
List<String> lines = Files.readAllLines(Paths.get(filename));

for (String line : lines) {
line = line.trim();
if (line.isEmpty() || line.startsWith("#")) {
continue;
}

String[] parts = line.split(",");
if (parts.length == 3) {
String symbol = parts[0];
String name = parts[1];
BigDecimal price = new BigDecimal(parts[2]);

stocks.add(new Stock(symbol, name, price));
}
}
return stocks; // returnerer listen
return Files.readAllLines(Paths.get(filename)).stream()
.map(String::trim)
.filter(line -> !line.isEmpty() && !line.startsWith("#"))
.map(line -> line.split(","))
.filter(parts -> parts.length == 3)
.map(parts -> new Stock(parts[0], parts[1], new BigDecimal(parts[2])))
.toList();
}

// lagring
public void saveStocksToFile(String filename, List<Stock> stocks) throws IOException {
List<String> lines = new ArrayList<>();

// header
lines.add("# Ticker,Name,Price");

for (Stock stock : stocks) {
// formaterer hver aksje som "SYMBOL,NAME,PRICE"
String line = String.format("%s,%s,%s",

lines.addAll(stocks.stream()
.map(stock -> String.format("%s,%s,%s",
stock.getSymbol(),
stock.getCompany(),
stock.getSalesPrice().toString());
lines.add(line);
}

stock.getSalesPrice().toString()))
.toList());

Files.write(Paths.get(filename), lines);
}
}
19 changes: 6 additions & 13 deletions src/main/java/Model/Portfolio.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,9 @@ public List<Share> getShares(String symbol) {
if (symbol == null || symbol.isBlank()) {
throw new IllegalArgumentException("Symbol cannot be null or blank");
}
List<Share> result = new ArrayList<>();
for (Share share : shares) {
if (share.getStock().getSymbol().equals(symbol)) {
result.add(share);
}
}
return result;
return shares.stream()
.filter(share -> share.getStock().getSymbol().equals(symbol))
.toList();
}

public boolean contains(Share share) {
Expand All @@ -50,12 +46,9 @@ public boolean contains(Share share) {
}

public BigDecimal getNetWorth() {
BigDecimal total = BigDecimal.ZERO;
for (Share share : shares) {
SaleCalculator calc = new SaleCalculator(share);
total = total.add(calc.calculateTotal());
}
return total;
return shares.stream()
.map(share -> new SaleCalculator(share).calculateTotal())
.reduce(BigDecimal.ZERO, BigDecimal::add);
}

}
234 changes: 223 additions & 11 deletions src/test/java/ExchangeTest.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import Model.Exchange;
import Model.Player;
import Model.Share;
import Model.Stock;
import Model.Transaction;
import Model.Purchase;
import Model.Sale;

import static org.junit.jupiter.api.Assertions.*;

Expand All @@ -15,39 +20,246 @@ public class ExchangeTest {
private Exchange exchange;
private Stock apple;
private Stock google;
private Player player;

@BeforeAll
public void setUp() {
@BeforeEach
void setUp() {
apple = new Stock("AAPL", "Apple", new BigDecimal("100"));
google = new Stock("GOOGL", "Google", new BigDecimal("200"));

List<Stock> stocks = new ArrayList<>();
stocks.add(apple);
stocks.add(google);

exchange = new Exchange("ABC", stocks);
exchange = new Exchange("TestExchange", stocks);
player = new Player("Jane", new BigDecimal("500000"));
}

// ---- Positive tests ----

@Test
public void testFindStocksBySymbol() {
List<Stock> result = exchange.findStocks("AAPL");
void testGetName() {
assertEquals("TestExchange", exchange.getName());
}

@Test
void testInitialWeekIsOne() {
assertEquals(1, exchange.getWeek());
}

@Test
void testAdvanceIncrementsWeek() {
exchange.advance();
assertEquals(2, exchange.getWeek());
}

@Test
void testHasStockReturnsTrue() {
assertTrue(exchange.hasStock("AAPL"));
}

@Test
void testHasStockReturnsFalse() {
assertFalse(exchange.hasStock("MSFT"));
}

@Test
void testGetStockReturnsCorrectStock() {
assertEquals(apple, exchange.getStock("AAPL"));
}

@Test
void testGetStockReturnsNullForUnknown() {
assertNull(exchange.getStock("MSFT"));
}

@Test
void testFindStocksBySymbol() {
List<Stock> result = exchange.findStocks("AAPL");
assertEquals(1, result.size());
assertEquals("AAPL", result.get(0).getSymbol());
}

@Test
public void testFindStocksByCompanyNames() {
void testFindStocksByCompanyName() {
List<Stock> result = exchange.findStocks("e");

assertEquals(2, result.size());
}

@Test
public void testFindStocksNotInList() {
void testFindStocksNoMatch() {
List<Stock> result = exchange.findStocks("Samsung");

assertEquals(0, result.size());
}


@Test
void testFindStocksEmptyTermReturnsAll() {
List<Stock> result = exchange.findStocks("");
assertEquals(2, result.size());
}

@Test
void testBuyReturnsCommittedPurchase() {
Transaction t = exchange.buy("AAPL", new BigDecimal("5"), player);
assertNotNull(t);
assertTrue(t.isCommitted());
assertInstanceOf(Purchase.class, t);
}

@Test
void testBuyDeductsMoneyFromPlayer() {
BigDecimal before = player.getMoney();
exchange.buy("AAPL", new BigDecimal("5"), player);
assertTrue(player.getMoney().compareTo(before) < 0);
}

@Test
void testBuyAddsShareToPortfolio() {
exchange.buy("AAPL", new BigDecimal("5"), player);
assertFalse(player.getPortfolio().getShares("AAPL").isEmpty());
}

@Test
void testSellReturnsCommittedSale() {
exchange.buy("AAPL", new BigDecimal("5"), player);
Share share = player.getPortfolio().getShares("AAPL").get(0);

Transaction t = exchange.sell(share, player);
assertNotNull(t);
assertTrue(t.isCommitted());
assertInstanceOf(Sale.class, t);
}

@Test
void testSellAddsMoney() {
exchange.buy("AAPL", new BigDecimal("5"), player);
Share share = player.getPortfolio().getShares("AAPL").get(0);
BigDecimal before = player.getMoney();

exchange.sell(share, player);
assertTrue(player.getMoney().compareTo(before) > 0);
}

@Test
void testSellRemovesShareFromPortfolio() {
exchange.buy("AAPL", new BigDecimal("5"), player);
Share share = player.getPortfolio().getShares("AAPL").get(0);

exchange.sell(share, player);
assertTrue(player.getPortfolio().getShares("AAPL").isEmpty());
}

@Test
void testGetGainersReturnsRequestedLimit() {
exchange.advance(); // prices must have changed at least once for a meaningful sort
List<Stock> gainers = exchange.getGainers(1);
assertEquals(1, gainers.size());
}

@Test
void testGetLosersReturnsRequestedLimit() {
exchange.advance();
List<Stock> losers = exchange.getLosers(1);
assertEquals(1, losers.size());
}

// ---- Negative tests ----

@Test
void testConstructorNullNameThrows() {
assertThrows(IllegalArgumentException.class, () ->
new Exchange(null, List.of(apple))
);
}

@Test
void testConstructorBlankNameThrows() {
assertThrows(IllegalArgumentException.class, () ->
new Exchange(" ", List.of(apple))
);
}

@Test
void testConstructorNullStockListThrows() {
assertThrows(IllegalArgumentException.class, () ->
new Exchange("X", null)
);
}

@Test
void testConstructorNullStockEntryThrows() {
List<Stock> withNull = new ArrayList<>();
withNull.add(apple);
withNull.add(null);
assertThrows(IllegalArgumentException.class, () ->
new Exchange("X", withNull)
);
}

@Test
void testBuyNullSymbolThrows() {
assertThrows(IllegalArgumentException.class, () ->
exchange.buy(null, new BigDecimal("5"), player)
);
}

@Test
void testBuyUnknownSymbolThrows() {
assertThrows(IllegalArgumentException.class, () ->
exchange.buy("MSFT", new BigDecimal("5"), player)
);
}

@Test
void testBuyZeroQuantityThrows() {
assertThrows(IllegalArgumentException.class, () ->
exchange.buy("AAPL", BigDecimal.ZERO, player)
);
}

@Test
void testBuyNegativeQuantityThrows() {
assertThrows(IllegalArgumentException.class, () ->
exchange.buy("AAPL", new BigDecimal("-1"), player)
);
}

@Test
void testBuyNullPlayerThrows() {
assertThrows(IllegalArgumentException.class, () ->
exchange.buy("AAPL", new BigDecimal("5"), null)
);
}

@Test
void testBuyInsufficientFundsThrows() {
Player poorPlayer = new Player("Broke", new BigDecimal("1"));
assertThrows(IllegalStateException.class, () ->
exchange.buy("AAPL", new BigDecimal("5"), poorPlayer)
);
}

@Test
void testSellNullPlayerThrows() {
exchange.buy("AAPL", new BigDecimal("5"), player);
Share share = player.getPortfolio().getShares("AAPL").get(0);
assertThrows(IllegalArgumentException.class, () ->
exchange.sell(share, null)
);
}

@Test
void testSellShareNotInPortfolioThrows() {
Share unowned = new Share(apple, new BigDecimal("1"), new BigDecimal("100"));
assertThrows(IllegalStateException.class, () ->
exchange.sell(unowned, player)
);
}

@Test
void testAddNullObserverThrows() {
assertThrows(IllegalArgumentException.class, () ->
exchange.addObserver(null)
);
}
}
Loading