From 84c1a03dc57374409de9fd10b4c0bbfaf0d7e3a2 Mon Sep 17 00:00:00 2001 From: Nikollai Date: Sun, 12 Apr 2026 15:06:28 +0200 Subject: [PATCH 1/6] Moved parsing of stock information to csvStockFileParser and added format verification to allow for other file formats in the future --- .../controller/CSVStockFileParser.java | 40 +++++++++++++++++++ .../controller/StockInformationReader.java | 21 ++-------- 2 files changed, 44 insertions(+), 17 deletions(-) create mode 100644 src/main/java/millions/controller/CSVStockFileParser.java diff --git a/src/main/java/millions/controller/CSVStockFileParser.java b/src/main/java/millions/controller/CSVStockFileParser.java new file mode 100644 index 0000000..fc39da8 --- /dev/null +++ b/src/main/java/millions/controller/CSVStockFileParser.java @@ -0,0 +1,40 @@ +package millions.controller; + +import millions.model.Stock; + +import javax.swing.*; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +public class CSVStockFileParser { + private List lines; + + public CSVStockFileParser(List lines) { + if (verifyCSV(lines)) { + this.lines = lines; + } + else { + // throw file format error + } + } + + // returns true if all entries have exactly 3 data points + private static boolean verifyCSV(List lines) { + return lines.stream() + .filter(l -> !(l.startsWith("#") || l.isEmpty())) + .anyMatch(l -> l.split(",").length != 3); + } + + public List parse() { + List stocks = new ArrayList<>(); + lines.forEach(l -> { + String[] split = l.split(","); + String symbol = split[0]; + String company = split[1]; + BigDecimal price = new BigDecimal(split[2]); + stocks.add(new Stock(symbol, company, price)); + }); + return stocks; + } +} diff --git a/src/main/java/millions/controller/StockInformationReader.java b/src/main/java/millions/controller/StockInformationReader.java index 0e98210..c942461 100644 --- a/src/main/java/millions/controller/StockInformationReader.java +++ b/src/main/java/millions/controller/StockInformationReader.java @@ -15,26 +15,13 @@ public StockInformationReader(File file) { this.file = file; } - public List readFile() { - List stocks = new ArrayList<>(); + public List readFile() { + List lines = new ArrayList<>(); try (Reader reader = new FileReader(file); BufferedReader bufferedReader = new BufferedReader(reader)) { - List lines = bufferedReader.readAllLines(); - for (String line : lines) { - // Skips comment and blank lines - if ( !(line.startsWith("#") || line.isEmpty()) ) { - String[] data = line.split(","); - // Ensures only fields of the correct length are read - if (data.length == 3) { - String symbol = data[0]; - String company = data[1]; - BigDecimal price = new BigDecimal(data[2]); - stocks.add(new Stock(symbol, company, price)); - } - } - } + lines = bufferedReader.readAllLines(); } catch (IOException e) { e.printStackTrace(); } - return stocks; + return lines; } } \ No newline at end of file From ea0abe1fae724516736b4ac5aeb7edb12afa0c8f Mon Sep 17 00:00:00 2001 From: Nikollai Date: Sun, 12 Apr 2026 15:33:51 +0200 Subject: [PATCH 2/6] Created StockFileWriter interface and moved csv write to its own file to open up for additional formats in the future --- .../controller/CSVStockFileWriter.java | 35 +++++++++++++++++++ .../millions/controller/StockFileWriter.java | 8 +++++ .../controller/StockInformationWriter.java | 34 ------------------ 3 files changed, 43 insertions(+), 34 deletions(-) create mode 100644 src/main/java/millions/controller/CSVStockFileWriter.java create mode 100644 src/main/java/millions/controller/StockFileWriter.java delete mode 100644 src/main/java/millions/controller/StockInformationWriter.java diff --git a/src/main/java/millions/controller/CSVStockFileWriter.java b/src/main/java/millions/controller/CSVStockFileWriter.java new file mode 100644 index 0000000..ceb4677 --- /dev/null +++ b/src/main/java/millions/controller/CSVStockFileWriter.java @@ -0,0 +1,35 @@ +package millions.controller; + +import millions.model.Stock; + +import java.io.FileWriter; +import java.util.ArrayList; +import java.util.List; + +public class CSVStockFileWriter implements StockFileWriter { + List stocks; + String finalString; + + public CSVStockFileWriter(List stocks) { + this.stocks = stocks; + } + + @Override + public void formatString() { + StringBuilder builder = new StringBuilder(); + stocks.forEach(stock -> { + builder.append(stock.getSymbol()); + builder.append(","); + builder.append(stock.getCompany()); + builder.append(","); + builder.append(stock.getLatestPriceChange().toString()); + }); + this.finalString = builder.toString(); + } + + @Override + public boolean write(){ + // TODO: handle file creation/file selection when writing to file + return false; + } +} diff --git a/src/main/java/millions/controller/StockFileWriter.java b/src/main/java/millions/controller/StockFileWriter.java new file mode 100644 index 0000000..2e2046d --- /dev/null +++ b/src/main/java/millions/controller/StockFileWriter.java @@ -0,0 +1,8 @@ +package millions.controller; + +import java.util.List; + +public interface StockFileWriter { + public void formatString(); + public boolean write(); +} diff --git a/src/main/java/millions/controller/StockInformationWriter.java b/src/main/java/millions/controller/StockInformationWriter.java deleted file mode 100644 index 692bc75..0000000 --- a/src/main/java/millions/controller/StockInformationWriter.java +++ /dev/null @@ -1,34 +0,0 @@ -package millions.controller; - -import millions.model.Stock; - -import java.io.*; -import java.util.List; - -public class StockInformationWriter { - private final List stocks; - private final File destinationFile; - - public StockInformationWriter(List stocks, File destinationFile) { - this.stocks = stocks; - this.destinationFile = destinationFile; - } - - public void write() { - StringBuilder builder = new StringBuilder(); - for (Stock stock : stocks) { - builder.append(stock.getSymbol()); - builder.append(","); - builder.append(stock.getCompany()); - builder.append(","); - // Unsure if price history or just latest price should be saved - builder.append(stock.getSalesPrice().toPlainString()); - builder.append("\n"); - } - try (FileWriter writer = new FileWriter(destinationFile); BufferedWriter bufferedWriter = new BufferedWriter(writer)) { - bufferedWriter.write(builder.toString()); - } catch (IOException e) { - e.printStackTrace(); - } - } -} From 764750a5f504b7016a22f15788ba28a684489d4f Mon Sep 17 00:00:00 2001 From: Nikollai Date: Sun, 12 Apr 2026 15:38:45 +0200 Subject: [PATCH 3/6] moved IO files to their own package --- .../millions/controller/{ => fileIO}/CSVStockFileParser.java | 3 +-- .../millions/controller/{ => fileIO}/CSVStockFileWriter.java | 4 +--- .../millions/controller/{ => fileIO}/StockFileWriter.java | 4 +--- .../controller/{ => fileIO}/StockInformationReader.java | 5 +---- 4 files changed, 4 insertions(+), 12 deletions(-) rename src/main/java/millions/controller/{ => fileIO}/CSVStockFileParser.java (94%) rename src/main/java/millions/controller/{ => fileIO}/CSVStockFileWriter.java (89%) rename src/main/java/millions/controller/{ => fileIO}/StockFileWriter.java (63%) rename src/main/java/millions/controller/{ => fileIO}/StockInformationReader.java (85%) diff --git a/src/main/java/millions/controller/CSVStockFileParser.java b/src/main/java/millions/controller/fileIO/CSVStockFileParser.java similarity index 94% rename from src/main/java/millions/controller/CSVStockFileParser.java rename to src/main/java/millions/controller/fileIO/CSVStockFileParser.java index fc39da8..15742db 100644 --- a/src/main/java/millions/controller/CSVStockFileParser.java +++ b/src/main/java/millions/controller/fileIO/CSVStockFileParser.java @@ -1,8 +1,7 @@ -package millions.controller; +package millions.controller.fileIO; import millions.model.Stock; -import javax.swing.*; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/millions/controller/CSVStockFileWriter.java b/src/main/java/millions/controller/fileIO/CSVStockFileWriter.java similarity index 89% rename from src/main/java/millions/controller/CSVStockFileWriter.java rename to src/main/java/millions/controller/fileIO/CSVStockFileWriter.java index ceb4677..7f602ba 100644 --- a/src/main/java/millions/controller/CSVStockFileWriter.java +++ b/src/main/java/millions/controller/fileIO/CSVStockFileWriter.java @@ -1,9 +1,7 @@ -package millions.controller; +package millions.controller.fileIO; import millions.model.Stock; -import java.io.FileWriter; -import java.util.ArrayList; import java.util.List; public class CSVStockFileWriter implements StockFileWriter { diff --git a/src/main/java/millions/controller/StockFileWriter.java b/src/main/java/millions/controller/fileIO/StockFileWriter.java similarity index 63% rename from src/main/java/millions/controller/StockFileWriter.java rename to src/main/java/millions/controller/fileIO/StockFileWriter.java index 2e2046d..6b61251 100644 --- a/src/main/java/millions/controller/StockFileWriter.java +++ b/src/main/java/millions/controller/fileIO/StockFileWriter.java @@ -1,6 +1,4 @@ -package millions.controller; - -import java.util.List; +package millions.controller.fileIO; public interface StockFileWriter { public void formatString(); diff --git a/src/main/java/millions/controller/StockInformationReader.java b/src/main/java/millions/controller/fileIO/StockInformationReader.java similarity index 85% rename from src/main/java/millions/controller/StockInformationReader.java rename to src/main/java/millions/controller/fileIO/StockInformationReader.java index c942461..38a2173 100644 --- a/src/main/java/millions/controller/StockInformationReader.java +++ b/src/main/java/millions/controller/fileIO/StockInformationReader.java @@ -1,9 +1,6 @@ -package millions.controller; - -import millions.model.Stock; +package millions.controller.fileIO; import java.io.*; -import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; From 3acdb6a6f8da331f7e3c94530b4ec7add431c8d1 Mon Sep 17 00:00:00 2001 From: Nikollai Date: Sun, 12 Apr 2026 16:34:20 +0200 Subject: [PATCH 4/6] Changelog renamed StockFileReader Added toString method to stock class Created test for CSVStockFileParser Fixed issue where CSVStockFileParser would only accept incorrect formats --- .../controller/fileIO/CSVStockFileParser.java | 9 +++-- ...mationReader.java => StockFileReader.java} | 10 +++-- src/main/java/millions/model/Stock.java | 5 +++ .../java/millions/CSVStockFileParserTest.java | 40 +++++++++++++++++++ 4 files changed, 56 insertions(+), 8 deletions(-) rename src/main/java/millions/controller/fileIO/{StockInformationReader.java => StockFileReader.java} (68%) create mode 100644 src/test/java/millions/CSVStockFileParserTest.java diff --git a/src/main/java/millions/controller/fileIO/CSVStockFileParser.java b/src/main/java/millions/controller/fileIO/CSVStockFileParser.java index 15742db..536e142 100644 --- a/src/main/java/millions/controller/fileIO/CSVStockFileParser.java +++ b/src/main/java/millions/controller/fileIO/CSVStockFileParser.java @@ -19,15 +19,16 @@ public CSVStockFileParser(List lines) { } // returns true if all entries have exactly 3 data points - private static boolean verifyCSV(List lines) { + public boolean verifyCSV(List lines) { return lines.stream() - .filter(l -> !(l.startsWith("#") || l.isEmpty())) - .anyMatch(l -> l.split(",").length != 3); + .filter(l -> !(l.startsWith("#") || l.isBlank())) + .noneMatch(l -> l.split(",").length != 3); + } public List parse() { List stocks = new ArrayList<>(); - lines.forEach(l -> { + lines.stream().filter(l -> !((l.startsWith("#") || l.isBlank()))).forEach(l -> { String[] split = l.split(","); String symbol = split[0]; String company = split[1]; diff --git a/src/main/java/millions/controller/fileIO/StockInformationReader.java b/src/main/java/millions/controller/fileIO/StockFileReader.java similarity index 68% rename from src/main/java/millions/controller/fileIO/StockInformationReader.java rename to src/main/java/millions/controller/fileIO/StockFileReader.java index 38a2173..22852cf 100644 --- a/src/main/java/millions/controller/fileIO/StockInformationReader.java +++ b/src/main/java/millions/controller/fileIO/StockFileReader.java @@ -1,18 +1,20 @@ package millions.controller.fileIO; import java.io.*; +import java.nio.file.Path; import java.util.ArrayList; import java.util.List; -public class StockInformationReader { - private final File file; +public class StockFileReader { + private final Path filePath; - public StockInformationReader(File file) { - this.file = file; + public StockFileReader(Path path) { + this.filePath = path; } public List readFile() { + File file = new File(filePath.toString()); List lines = new ArrayList<>(); try (Reader reader = new FileReader(file); BufferedReader bufferedReader = new BufferedReader(reader)) { lines = bufferedReader.readAllLines(); diff --git a/src/main/java/millions/model/Stock.java b/src/main/java/millions/model/Stock.java index feff8bb..2a67d74 100644 --- a/src/main/java/millions/model/Stock.java +++ b/src/main/java/millions/model/Stock.java @@ -73,4 +73,9 @@ public BigDecimal getLatestPriceChange() { return currentPrice.subtract(lastPrice); } + + @Override + public String toString() { + return "Stock [symbol: " + symbol + ", company: " + company + ", prices: " + prices + "]"; + } } diff --git a/src/test/java/millions/CSVStockFileParserTest.java b/src/test/java/millions/CSVStockFileParserTest.java new file mode 100644 index 0000000..2b53311 --- /dev/null +++ b/src/test/java/millions/CSVStockFileParserTest.java @@ -0,0 +1,40 @@ +package millions; + +import millions.controller.fileIO.CSVStockFileParser; +import millions.controller.fileIO.StockFileReader; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class CSVStockFileParserTest { + @TempDir + static Path tempDir; + + static Path sharedFile; + + @BeforeAll + public static void setUpTestFile() throws Exception { + sharedFile = Files.createFile(tempDir.resolve("file.csv")); + String string = "# Top 500 US Stocks by Market Cap\n"; + string += "# Ticker,Name,Price\n"; + string += "\n"; + string += "NVDA,Nvidia,191.27\n"; + string += "AAPL,Apple Inc.,276.43\n"; + string += "MSFT,Microsoft,404.68\n"; + Files.writeString(sharedFile, string); + } + + @Test + public void parseStockFileTest(){ + StockFileReader stockFileReader = new StockFileReader(sharedFile); + stockFileReader.readFile().forEach(System.out::println); + + CSVStockFileParser parser = new CSVStockFileParser(stockFileReader.readFile()); + parser.parse().forEach(s -> System.out.println(s.toString())); + } +} From 49ac7b1cdab3583fd230d77cb8d08fbcf6905a4b Mon Sep 17 00:00:00 2001 From: Nikollai Date: Sun, 12 Apr 2026 16:41:05 +0200 Subject: [PATCH 5/6] fixed CSVStockFileParserTest Created StockFileReaderTest --- .../java/millions/CSVStockFileParserTest.java | 5 +-- .../java/millions/StockFileReaderTest.java | 35 +++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 src/test/java/millions/StockFileReaderTest.java diff --git a/src/test/java/millions/CSVStockFileParserTest.java b/src/test/java/millions/CSVStockFileParserTest.java index 2b53311..8cb459b 100644 --- a/src/test/java/millions/CSVStockFileParserTest.java +++ b/src/test/java/millions/CSVStockFileParserTest.java @@ -11,6 +11,8 @@ import java.nio.file.Files; import java.nio.file.Path; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class CSVStockFileParserTest { @TempDir static Path tempDir; @@ -32,9 +34,8 @@ public static void setUpTestFile() throws Exception { @Test public void parseStockFileTest(){ StockFileReader stockFileReader = new StockFileReader(sharedFile); - stockFileReader.readFile().forEach(System.out::println); CSVStockFileParser parser = new CSVStockFileParser(stockFileReader.readFile()); - parser.parse().forEach(s -> System.out.println(s.toString())); + assertEquals(3, parser.parse().size()); } } diff --git a/src/test/java/millions/StockFileReaderTest.java b/src/test/java/millions/StockFileReaderTest.java new file mode 100644 index 0000000..c40e4ca --- /dev/null +++ b/src/test/java/millions/StockFileReaderTest.java @@ -0,0 +1,35 @@ +package millions; + +import millions.controller.fileIO.StockFileReader; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class StockFileReaderTest { + @TempDir + static Path tempDir; + + static Path sharedFile; + @BeforeAll + public static void setUpTestFile() throws Exception { + sharedFile = Files.createFile(tempDir.resolve("file.csv")); + String string = "# Top 500 US Stocks by Market Cap\n"; + string += "# Ticker,Name,Price\n"; + string += "\n"; + string += "NVDA,Nvidia,191.27\n"; + string += "AAPL,Apple Inc.,276.43\n"; + string += "MSFT,Microsoft,404.68\n"; + Files.writeString(sharedFile, string); + } + + @Test + public void testReadStockFile() throws Exception { + StockFileReader stockFileReader = new StockFileReader(sharedFile); + assertEquals(6, stockFileReader.readFile().size()); + } +} From 9f127acb76d2f8c9ae59bb1aad202a94a34c5a4d Mon Sep 17 00:00:00 2001 From: Nikollai Date: Mon, 13 Apr 2026 14:21:59 +0200 Subject: [PATCH 6/6] Fixed CSVStockFileWriter Created CSVStockFileWriterTest Made some small changes to StockFileWriter and StockFileReaderTest --- .../controller/fileIO/CSVStockFileParser.java | 4 +- .../controller/fileIO/CSVStockFileWriter.java | 20 ++++++--- .../controller/fileIO/StockFileWriter.java | 4 +- .../java/millions/CSVStockFileWriterTest.java | 43 +++++++++++++++++++ .../java/millions/StockFileReaderTest.java | 2 +- 5 files changed, 65 insertions(+), 8 deletions(-) create mode 100644 src/test/java/millions/CSVStockFileWriterTest.java diff --git a/src/main/java/millions/controller/fileIO/CSVStockFileParser.java b/src/main/java/millions/controller/fileIO/CSVStockFileParser.java index 536e142..5a0cee0 100644 --- a/src/main/java/millions/controller/fileIO/CSVStockFileParser.java +++ b/src/main/java/millions/controller/fileIO/CSVStockFileParser.java @@ -28,7 +28,9 @@ public boolean verifyCSV(List lines) { public List parse() { List stocks = new ArrayList<>(); - lines.stream().filter(l -> !((l.startsWith("#") || l.isBlank()))).forEach(l -> { + lines.stream() + .filter(l -> !((l.startsWith("#") || l.isBlank()))) + .forEach(l -> { String[] split = l.split(","); String symbol = split[0]; String company = split[1]; diff --git a/src/main/java/millions/controller/fileIO/CSVStockFileWriter.java b/src/main/java/millions/controller/fileIO/CSVStockFileWriter.java index 7f602ba..463ea04 100644 --- a/src/main/java/millions/controller/fileIO/CSVStockFileWriter.java +++ b/src/main/java/millions/controller/fileIO/CSVStockFileWriter.java @@ -2,11 +2,15 @@ import millions.model.Stock; +import java.io.BufferedWriter; +import java.io.*; +import java.nio.file.Path; import java.util.List; +//TODO: Validation of data before writing public class CSVStockFileWriter implements StockFileWriter { - List stocks; - String finalString; + private final List stocks; + private String finalString; public CSVStockFileWriter(List stocks) { this.stocks = stocks; @@ -20,14 +24,20 @@ public void formatString() { builder.append(","); builder.append(stock.getCompany()); builder.append(","); - builder.append(stock.getLatestPriceChange().toString()); + builder.append(stock.getSalesPrice().toString()); + builder.append("\n"); }); this.finalString = builder.toString(); } @Override - public boolean write(){ - // TODO: handle file creation/file selection when writing to file + public boolean write(Path path){ + try (FileWriter fw = new FileWriter(path.toString()); BufferedWriter writer = new BufferedWriter(fw);) { + this.formatString(); + writer.write(finalString); + } catch (IOException e) { + e.printStackTrace(); + } return false; } } diff --git a/src/main/java/millions/controller/fileIO/StockFileWriter.java b/src/main/java/millions/controller/fileIO/StockFileWriter.java index 6b61251..32a8e13 100644 --- a/src/main/java/millions/controller/fileIO/StockFileWriter.java +++ b/src/main/java/millions/controller/fileIO/StockFileWriter.java @@ -1,6 +1,8 @@ package millions.controller.fileIO; +import java.nio.file.Path; + public interface StockFileWriter { public void formatString(); - public boolean write(); + public boolean write(Path path); } diff --git a/src/test/java/millions/CSVStockFileWriterTest.java b/src/test/java/millions/CSVStockFileWriterTest.java new file mode 100644 index 0000000..6765f7a --- /dev/null +++ b/src/test/java/millions/CSVStockFileWriterTest.java @@ -0,0 +1,43 @@ +package millions; + +import millions.controller.fileIO.CSVStockFileWriter; +import millions.controller.fileIO.StockFileReader; +import millions.model.Stock; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.math.BigDecimal; +import java.nio.file.Path; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class CSVStockFileWriterTest { + @TempDir + static Path tempDir; + + List stocks; + + @BeforeEach + void setup() { + Stock s1 = new Stock("PEAR", "Pear Inc.", BigDecimal.valueOf(300)); + Stock s2 = new Stock("DOGL", "DOOGLE Inc.", BigDecimal.valueOf(200.00)); + Stock s3 = new Stock("MSFT", "EpsteinSoft Inc.", BigDecimal.valueOf(0.02)); + + this.stocks = List.of(s1, s2, s3); + } + + @Test + public void testWrite() { + for(Stock stock : this.stocks) { + System.out.println(stock.toString()); + } + CSVStockFileWriter csvStockFileWriter = new CSVStockFileWriter(stocks); + csvStockFileWriter.write(tempDir.resolve("stocks.csv")); + + StockFileReader stockFileReader = new StockFileReader(tempDir.resolve("stocks.csv")); + assertEquals(3, stockFileReader.readFile().size()); + } +} diff --git a/src/test/java/millions/StockFileReaderTest.java b/src/test/java/millions/StockFileReaderTest.java index c40e4ca..bfb9a8d 100644 --- a/src/test/java/millions/StockFileReaderTest.java +++ b/src/test/java/millions/StockFileReaderTest.java @@ -28,7 +28,7 @@ public static void setUpTestFile() throws Exception { } @Test - public void testReadStockFile() throws Exception { + public void testReadStockFile() { StockFileReader stockFileReader = new StockFileReader(sharedFile); assertEquals(6, stockFileReader.readFile().size()); }