Skip to content

Commit

Permalink
Merge pull request #50 from IDATT2003-gruppe06/file-io-development
Browse files Browse the repository at this point in the history
Added: JavaDoc, Logger, Unit tests, and cleaned up exception messages
  • Loading branch information
nolydvo authored May 18, 2026
2 parents 88c9c53 + 6e01d27 commit 3f6b4ff
Show file tree
Hide file tree
Showing 9 changed files with 130 additions and 73 deletions.
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.

0 comments on commit 3f6b4ff

Please sign in to comment.