diff --git a/src/main/java/edu/ntnu/idi/idatt/Exchange.java b/src/main/java/edu/ntnu/idi/idatt/Exchange.java
index f4a8d79..7214ffa 100644
--- a/src/main/java/edu/ntnu/idi/idatt/Exchange.java
+++ b/src/main/java/edu/ntnu/idi/idatt/Exchange.java
@@ -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;
@@ -20,7 +22,7 @@
*
*
*/
-public class Exchange {
+public class Exchange extends ExchangeLoader {
private final String name;
private int week;
@@ -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 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);
}
}
@@ -58,6 +63,10 @@ public int getWeek() {
return week;
}
+ public List getStocks() {
+ return stockMap.values().stream().toList();
+ }
+
/**
* Method for checking if a specific stock exists in the exchange.
*
@@ -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);
+ }
}
}
diff --git a/src/main/java/edu/ntnu/idi/idatt/file/ExchangeLoader.java b/src/main/java/edu/ntnu/idi/idatt/file/ExchangeLoader.java
new file mode 100644
index 0000000..5f50a6a
--- /dev/null
+++ b/src/main/java/edu/ntnu/idi/idatt/file/ExchangeLoader.java
@@ -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
+ *
+ *
+ * Utilizes method overloading for different types
+ * of path formatting.
+ *
+ *
+ * @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 of loaded stocks.
+ * @throws IOException on BufferedReader error
+ */
+ protected List load() throws IOException {
+
+ ArrayList stocks = new ArrayList<>();
+
+ try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
+ List 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 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!");
+ }
+
+ }
+
+}
diff --git a/src/test/java/edu/ntnu/idi/idatt/ExchangeTest.java b/src/test/java/edu/ntnu/idi/idatt/ExchangeTest.java
index 64c4b35..02cb3d7 100644
--- a/src/test/java/edu/ntnu/idi/idatt/ExchangeTest.java
+++ b/src/test/java/edu/ntnu/idi/idatt/ExchangeTest.java
@@ -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;
@@ -17,22 +22,37 @@
class ExchangeTest {
+ /**
+ *
+ * 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.
+ *
+ */
private Exchange exchange;
private List 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"));
}
@@ -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 expected = List.of(stocks.get(0), stocks.get(3));
- //
- assertEquals(expected, exchange.findStocks("n"));
+ assertEquals(2, exchange.findStocks("n").size());
}
@@ -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"));
diff --git a/src/test/java/edu/ntnu/idi/idatt/file/ExchangeLoaderTest.java b/src/test/java/edu/ntnu/idi/idatt/file/ExchangeLoaderTest.java
new file mode 100644
index 0000000..94f5617
--- /dev/null
+++ b/src/test/java/edu/ntnu/idi/idatt/file/ExchangeLoaderTest.java
@@ -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
+ *
+ *
+ * Tests the loading and saving of stock data.
+ *
+ */
+class ExchangeLoaderTest {
+
+ private ExchangeLoader loader;
+ private List 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 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 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"));
+ }
+
+}
diff --git a/src/test/resources/stocks.csv b/src/test/resources/stocks.csv
new file mode 100644
index 0000000..275ddb0
--- /dev/null
+++ b/src/test/resources/stocks.csv
@@ -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
+
+