Skip to content

Finished issue file-handeling #21

Merged
merged 4 commits into from
Mar 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
24 changes: 20 additions & 4 deletions src/main/java/edu/ntnu/idi/idatt/Exchange.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package edu.ntnu.idi.idatt;

import edu.ntnu.idi.idatt.file.ExchangeLoader;
import edu.ntnu.idi.idatt.marked.Share;
import edu.ntnu.idi.idatt.marked.Stock;
import edu.ntnu.idi.idatt.transaction.Purchase;
import edu.ntnu.idi.idatt.transaction.Sale;
import edu.ntnu.idi.idatt.transaction.Transaction;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
Expand All @@ -20,7 +22,7 @@
* </p>
*
*/
public class Exchange {
public class Exchange extends ExchangeLoader {

private final String name;
private int week;
Expand All @@ -33,12 +35,15 @@ public class Exchange {
* @param name - Name of the current stock Exchange
* @param stocks - List of aviable stocks for this exchange.
*/
public Exchange(String name, List<Stock> stocks) {
public Exchange(String name, String path) {
super(path);
this.name = name;
this.week = 1;

for (Stock stock : stocks) {
stockMap.put(stock.getSymbol(), stock);
try {
this.load().forEach(stock -> stockMap.put(stock.getSymbol(), stock));
} catch (IOException e) {
throw new IllegalArgumentException("Problem loading [" + name + "] exchange : " + e);
}

}
Expand All @@ -58,6 +63,10 @@ public int getWeek() {
return week;
}

public List<Stock> getStocks() {
return stockMap.values().stream().toList();
}

/**
* Method for checking if a specific stock exists in the exchange.
*
Expand Down Expand Up @@ -194,6 +203,13 @@ public Transaction sell(Share share, Player player) {
public void advance() {
for (Stock stocks : stockMap.values()) {
stocks.addNewSalesPrice(BigDecimal.valueOf(random.nextDouble()));

// TODO: Move this to JavaFx on Window close?
try {
this.save(stockMap.values().stream().toList());
} catch (IOException e) {
throw new IllegalArgumentException("Problem loading [" + name + "] exchange : " + e);
}
}
}

Expand Down
100 changes: 100 additions & 0 deletions src/main/java/edu/ntnu/idi/idatt/file/ExchangeLoader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package edu.ntnu.idi.idatt.file;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import edu.ntnu.idi.idatt.marked.Stock;

public class ExchangeLoader {

private final File file;

/**
* Constructors for ExchangeLoader
*
* <p>
* Utilizes method overloading for different types
* of path formatting.
* </p>
*
* @throws IllegalArgumentException if specified path doesn't exist.
*/
protected ExchangeLoader(String path) {
file = new File(path);
if (!file.exists()) {
throw new IllegalArgumentException("File at this path doesn't exist!");
}
}

protected ExchangeLoader(URL path) {
file = new File(path.toString());
if (!file.exists()) {
throw new IllegalArgumentException("File at this path doesn't exist!");
}
}

/**
* Method for loading from stocks from file
*
* @return List<Stock> of loaded stocks.
* @throws IOException on BufferedReader error
*/
protected List<Stock> load() throws IOException {

ArrayList<Stock> stocks = new ArrayList<>();

try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
List<String> stockStringList = new ArrayList<>(reader.readAllLines());

// Remove comments
stockStringList.removeIf(s -> s.isBlank());
stockStringList.removeIf(s -> s.startsWith("#"));

for (String stockString : stockStringList) {
String[] stockValues = stockString.split(",");

// TODO: Loading all historical prices not the recent, saved one.
Stock stock = new Stock(stockValues[0], stockValues[1], List.of(new BigDecimal(stockValues[2])));
stocks.add(stock);
}

} catch (IOException e) {
throw new IOException("File loading failed!");
}

return stocks;

}

/**
* Method for saving stocks to file.
*
* @param stocks The destined list to be saved.
* @throws IOException on BufferedWriter error.
*/
protected void save(List<Stock> stocks) throws IOException {

try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {

for (Stock stock : stocks) {
String data = stock.getSymbol() + "," + stock.getCompany() + ","
+ stock.getHistoricalPrices().getLast().toString();
writer.write(data);
writer.newLine();
}

} catch (IOException e) {
throw new IOException("File saving failed!");
}

}

}
44 changes: 31 additions & 13 deletions src/test/java/edu/ntnu/idi/idatt/ExchangeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;

Expand All @@ -17,22 +22,37 @@

class ExchangeTest {

/**
* <p>
* Caution!
* stocks List is not sorted correctly.
* We parse it with hashMap.values().stream().toList
* which dont properly arrange it in memory.
* Take caution when programming or reading here.
*
* @see PTgetGainers_Losers don't take the get(index) literally
* but focus on the differences of last sale value made.
*
* This is a work around for implementing the ExchangeLoader to Exchange
* class.
* </p>
*/
private Exchange exchange;
private List<Stock> stocks;
private Player player;

@BeforeEach
public void PT_setup() {
public void PT_setup() throws IOException {

// Initialize exchange with proper objects
Stock AAPL = new Stock("AAPL", "Apple Inc.", List.of(new BigDecimal("32")));
Stock NVDA = new Stock("NVDA", "NVIDIA", List.of(new BigDecimal("182.81")));
Stock TSLA = new Stock("TSLA", "Tesla", List.of(new BigDecimal("417.44")));
Stock AMD = new Stock("AMD", "Advanced Micro Devices", List.of(new BigDecimal("207.32")));
InputStream is = getClass()
.getClassLoader()
.getResourceAsStream("stocks.csv");

stocks = List.of(AAPL, NVDA, TSLA, AMD);
Path tempFile = Files.createTempFile("stocks", ".csv");
Files.copy(is, tempFile, StandardCopyOption.REPLACE_EXISTING);

exchange = new Exchange("TestExchange", stocks);
exchange = new Exchange("TestExchange", tempFile.toFile().toPath().toString());
stocks = exchange.getStocks();
player = new Player("TestPlayer", new BigDecimal("500"));
}

Expand All @@ -55,12 +75,10 @@ void PTConstructor() {
void PTFindStock() {

assertTrue(exchange.hasStock("AAPL"));
assertEquals(stocks.get(0) /* AAPL Stock */, exchange.getStock("AAPL"));
assertTrue(stocks.contains(exchange.getStock("AAPL")));

// FindStocks for letter "n" should be - AAPL, AMD (both symbols and names!)
List<Stock> expected = List.of(stocks.get(0), stocks.get(3));
//
assertEquals(expected, exchange.findStocks("n"));
assertEquals(2, exchange.findStocks("n").size());

}

Expand Down Expand Up @@ -127,7 +145,7 @@ void PTAdvance() {
void PTgetGainers_Losers() {
// Simulate price change
stocks.get(0).addNewSalesPrice(new BigDecimal("4333"));
stocks.get(1).addNewSalesPrice(new BigDecimal("50"));
stocks.get(1).addNewSalesPrice(new BigDecimal("10"));
stocks.get(2).addNewSalesPrice(new BigDecimal("3"));
stocks.get(3).addNewSalesPrice(new BigDecimal("800"));

Expand Down
103 changes: 103 additions & 0 deletions src/test/java/edu/ntnu/idi/idatt/file/ExchangeLoaderTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package edu.ntnu.idi.idatt.file;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.List;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import edu.ntnu.idi.idatt.marked.Stock;

/**
* Test class for ExchangeLoader
*
* <p>
* Tests the loading and saving of stock data.
* </p>
*/
class ExchangeLoaderTest {

private ExchangeLoader loader;
private List<Stock> exampleStocks;

@BeforeEach
public void PT_setup() throws IOException {

InputStream is = getClass()
.getClassLoader()
.getResourceAsStream("stocks.csv");

Path tempFile = Files.createTempFile("stocks", ".csv");
Files.copy(is, tempFile, StandardCopyOption.REPLACE_EXISTING);

loader = new ExchangeLoader(tempFile.toFile().toPath().toString());

Stock AAPL = new Stock("AAPL", "Apple Inc.", List.of(new BigDecimal("32")));
Stock NVDA = new Stock("NVDA", "NVIDIA", List.of(new BigDecimal("182.81")));
Stock TSLA = new Stock("TSLA", "Tesla", List.of(new BigDecimal("417.44")));
Stock AMD = new Stock("AMD", "Advanced Micro Devices", List.of(new BigDecimal("207.32")));

exampleStocks = List.of(AAPL, NVDA, TSLA, AMD);
}

/**
* Positive test for loading/reading stocks
*/
@Test
void PT_load() {
List<Stock> stocks = null;
try {
stocks = loader.load();
} catch (IOException e) {
e.printStackTrace();
}

assertEquals(4, stocks.size());

}

/**
* Positive test for saving stocks.
*/
@Test
void PT_save() {
exampleStocks.get(3).addNewSalesPrice(new BigDecimal("99999"));

// Save

try {
loader.save(exampleStocks);
} catch (IOException e) {
e.printStackTrace();
}

// Try to read again
List<Stock> stocks = null;
try {
stocks = loader.load();
} catch (IOException e) {
e.printStackTrace();
}

assertEquals(new BigDecimal("99999"), stocks.get(3).getSalesPrice());

}

/**
* Negative tests for constructor
*/
@Test
void NT_IllegalArgumentException_Constructor() {
assertThrows(IllegalArgumentException.class,
() -> new ExchangeLoader("resources/notexistantfile.csv"));
}

}
7 changes: 7 additions & 0 deletions src/test/resources/stocks.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Ticker,Name,Price
AAPL,Apple Inc,32
NVDA,NVIDIA,182.81
TSLA,Tesla,417.44
AMD,Advanced Micro Devices,207.32