Skip to content

Commit

Permalink
Merge pull request #31 from solvena/30-change-into-lambdastreams
Browse files Browse the repository at this point in the history
Change into lambda/streams
  • Loading branch information
solvena authored May 25, 2026
2 parents 6cdac6f + 6d85031 commit e9a5a0f
Show file tree
Hide file tree
Showing 15 changed files with 975 additions and 192 deletions.
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

0 comments on commit e9a5a0f

Please sign in to comment.