Skip to content

Added: JavaDoc, Logger, Unit tests, and cleaned up exception messages #50

Merged
merged 6 commits into from
May 18, 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
11 changes: 8 additions & 3 deletions src/main/java/millions/App.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
package millions;

import java.math.BigDecimal;
import java.util.logging.Level;
import java.util.logging.Logger;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.stage.Stage;
import millions.controller.GameController;
import millions.controller.fileIO.CSV.CSVStockFileWriter;
import millions.controller.fileIO.InvalidFormatException;
import millions.view.GameView;
import millions.view.StartView;

/** Main JavaFX application entry point for the Millions stock trading game. */
public class App extends Application {

private static final Logger logger = Logger.getLogger(App.class.getName());
@Override
public void start(Stage stage) {
GameController controller = new GameController();
Expand All @@ -36,15 +40,16 @@ public void start(Stage stage) {
Scene gameScene = new Scene(gameView, 1920, 1080);
stage.setScene(gameScene);
} catch (InvalidFormatException e) {
logger.log(Level.WARNING, "InvalidFormatException: " + e.getMessage());
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setTitle("Error");
alert.setHeaderText("Error with selected file");
alert.setContentText("Please control the format of the selected file");
alert.setContentText(e.getMessage() + "\nPlease control the format of the selected file");

alert.showAndWait();

} catch (RuntimeException ex) {
System.err.println(ex);
logger.log(Level.SEVERE, ex.getMessage());
System.exit(0);
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
import java.nio.file.Path;
import java.util.List;

/**
* <p>Bundles StockFileReader and CSVStockFileParser together to reduce boilerplate code when reading stocks from a csv file</p>
*/
public class CSVFileHandler {
StockFileReader reader;
CSVStockFileParser parser;
Expand All @@ -16,6 +19,12 @@ public CSVFileHandler() {
this.parser = new CSVStockFileParser();
}

/**
* Reads and parses stocks from a csv file
* @param filePath Path to stock file
* @return list of stock object created from parsed file
* @throws InvalidFormatException Throws an InvalidFormatException received from parser
*/
public List<Stock> getStocksFromFile(Path filePath) {
try {
StockFileReader reader = new StockFileReader();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,52 @@ public class CSVStockFileParser {

public CSVStockFileParser() {}

// returns true if all entries have exactly 3 data points
/**
* Verifies the amount of data fields present in supplied CSV file.
*
* @param lines Lines from csv file
* @return Boolean: True if file satisfies expected format (3 fields)
*/
public boolean verifyCSV(List<String> lines) {
return lines.stream()
.filter(l -> !(l.startsWith("#") || l.isBlank()))
.noneMatch(l -> l.split(",").length != 3);
}

/**
* Parses the supplied lines if they satisfy the correct format expectations
*
* @param lines <p>lines to be parsed. <br>
* Each line must contain three data fields: String,String,BigDecimal <br>
* (Fields cannot be blank) <br>
* blank lines or lines beginning with '#' are ignored
* </p>
* @return List of stock objects created from the supplied lines
* @throws InvalidFormatException If one or more lines contain too many or too few data fields
* @throws InvalidFormatException If the BigDecimal field on one or more lines are not compatible
* @throws InvalidFormatException Upon recieving an IllegalArgumentException (Either Symbol or Company name is blank)
*/
public List<Stock> parse(List<String> lines) {
List<Stock> stocks = new ArrayList<>();
if (verifyCSV(lines)) {
lines.stream()
.filter(l -> !((l.startsWith("#") || l.isBlank())))
.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));
try {
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));
} catch (NumberFormatException e) {
throw new InvalidFormatException("Error with number conversion on line: " + l + "\n" + "Last field must be a number");
} catch (IllegalArgumentException e) {
throw new InvalidFormatException("Illegal argument on line: " + l + "\n" + e.getMessage());
}
});
} else {
throw new InvalidFormatException("Incorrect format for CSV File");
throw new InvalidFormatException("Incorrect format for CSV File: incorrect amount of data fields detected on one or more lines");
}
return stocks;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
package millions.controller.fileIO.CSV;

import millions.controller.fileIO.StockFileWriter;
import millions.model.Stock;

import java.io.BufferedWriter;
import java.io.*;
import java.io.BufferedWriter;
import java.nio.file.Path;
import java.util.List;
import java.util.logging.Logger;

import millions.controller.fileIO.StockFileWriter;
import millions.model.Stock;

//TODO: Validation of data before writing
/**
* Writes stock data to a CSV file.
* Implements StockFileWriter. <br>
* Converts a list of stock objects into a writeable string with a CSV format.
*
*/
public class CSVStockFileWriter implements StockFileWriter {
private final List<Stock> stocks;
private static final Logger logger = Logger.getLogger(CSVStockFileWriter.class.getName());
private String finalString;

public CSVStockFileWriter(List<Stock> stocks) {
this.stocks = stocks;
}
public CSVStockFileWriter() {}

/**
* Formats given string to CSV format to prepare for writing to file
*/
@Override
public void formatString() {
public String formatString(List<Stock> stocks) {
StringBuilder builder = new StringBuilder();
stocks.forEach(stock -> {
builder.append(stock.getSymbol());
Expand All @@ -31,16 +34,22 @@ public void formatString() {
builder.append(stock.getSalesPrice().toString());
builder.append("\n");
});
this.finalString = builder.toString();
return builder.toString();
}

/**
* Writes the saved string to a file
* @param stocks List of stock objects to write
* @param path Path to desired file
* @return Boolean for success
*/
@Override
public boolean write(Path path){
public boolean write(List<Stock> stocks, Path path){
try (FileWriter fw = new FileWriter(path.toString()); BufferedWriter writer = new BufferedWriter(fw);) {
this.formatString();
this.formatString(stocks);
writer.write(finalString);
} catch (IOException e) {
e.printStackTrace();
logger.severe(e.getMessage());
}
return false;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package millions.controller.fileIO;

/**
* Exception to be thrown when verifying the format of files
*/
public class InvalidFormatException extends RuntimeException {
public InvalidFormatException(String message) {
super(message);
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/millions/controller/fileIO/StockFileReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ public class StockFileReader {

public StockFileReader() {}

/**
* Reads the file found at the specified path
* @param path Path to the desired file
* @return List of each line in the file as a string
*/
public List<String> readFile(Path path) {
File file = new File(path.toString());
List<String> lines = new ArrayList<>();
Expand Down
7 changes: 5 additions & 2 deletions src/main/java/millions/controller/fileIO/StockFileWriter.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package millions.controller.fileIO;

import millions.model.Stock;

import java.nio.file.Path;
import java.util.List;

/**
* Interface for writing stock data to a file.
*/
public interface StockFileWriter {
public void formatString();
public boolean write(Path path);
String formatString(List<Stock> stocks);
boolean write(List<Stock> stocks, Path path);
}
48 changes: 45 additions & 3 deletions src/test/java/millions/CSVStockFileParserTest.java
Original file line number Diff line number Diff line change
@@ -1,33 +1,75 @@
package millions;

import millions.controller.fileIO.CSV.CSVStockFileParser;
import millions.controller.fileIO.InvalidFormatException;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;


import java.util.ArrayList;
import java.util.List;


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

public class CSVStockFileParserTest {

static String exampleString;
final CSVStockFileParser parser = new CSVStockFileParser();

@BeforeAll
public static void setUpTestFile() throws Exception {
public static void setUpTestString() {
exampleString = "# Top 500 US Stocks by Market Cap\n";
exampleString += "# Ticker,Name,Price\n";
exampleString += "\n";
exampleString += "NVDA,Nvidia,191.27\n";
exampleString += "AAPL,Apple Inc.,276.43\n";
exampleString += "MSFT,Microsoft,404.68\n";

}

@Test
public void parseStockFileTest(){
List<String> testList = List.of(exampleString.split("\n"));

CSVStockFileParser parser = new CSVStockFileParser();
assertEquals(3, parser.parse(testList).size());
}

@Test
public void InvalidFormatExceptionTest() {
exampleString += "Line with incorrect amount of data";
List<String> testList = List.of(exampleString.split("\n"));
Exception e = assertThrows(InvalidFormatException.class, () -> {parser.parse(testList);});
String expectedMessage = "Incorrect format for CSV File: incorrect amount of data fields detected on one or more lines";
assertEquals(expectedMessage, e.getMessage());
}

@Test
public void NumberConversionExceptionTest() {
exampleString += "Company, Company Inc., NotANumber";
List<String> testList = List.of(exampleString.split("\n"));
Exception e = assertThrows(InvalidFormatException.class, () -> {parser.parse(testList);});
String expectedMessage = "Error with number conversion on line: Company, Company Inc., NotANumber\n" +
"Last field must be a number";
assertEquals(expectedMessage, e.getMessage());
}

@Test
public void EmptySymbolFieldExceptionTest() {
exampleString += ",test,1";
List<String> testList = List.of(exampleString.split("\n"));
Exception e = assertThrows(InvalidFormatException.class, () -> {parser.parse(testList);});
String expectedMessage = "Illegal argument on line: ,test,1\n" +
"Symbol cannot be null or blank";
assertEquals(expectedMessage, e.getMessage());
}
@Test
public void EmptyCompanyNameFieldExceptionTest() {
exampleString += "test,,1";
List<String> testList = List.of(exampleString.split("\n"));
Exception e = assertThrows(InvalidFormatException.class, () -> {parser.parse(testList);});
String expectedMessage = "Illegal argument on line: test,,1\n" +
"Company cannot be null or blank";
assertEquals(expectedMessage, e.getMessage());
}
}
43 changes: 0 additions & 43 deletions src/test/java/millions/CSVStockFileWriterTest.java

This file was deleted.