stockSymbols = new ArrayList<>();
+
+ validStocks.forEach(s -> {
+ String[] lineElements = s.split(",");
+ String stockSymbol = lineElements[0].trim();
+ String stockName = lineElements[1].trim();
+ BigDecimal stockPrice = new BigDecimal(lineElements[2].trim());
+
+ try {
+ Stock stockObject = new Stock(stockSymbol, stockName, stockPrice);
+ if (!stockSymbols.contains(stockSymbol)) {
+ stockSymbols.add(stockSymbol);
+ stocksFromFile.add(stockObject);
+ }
+ } catch (IllegalArgumentException e) {
+ System.err.println("(" + s + ") is not a valid stock! Skipping...");
+ }
+
+ });
+ return stocksFromFile;
+ }
+
+ /**
+ * Converts a list of stocks to string representations of that stock.
+ *
+ * format: SYMBOL, NAME, PRICE
+ *
+ * @param stocks a list of {@link Stock} objects.
+ *
+ * @return a list of string representation of the stock objects.
+ * */
+ public List stocksToStrings(final List stocks) {
+ ArrayList stringList = new ArrayList<>();
+ stocks.forEach(s ->
+ stringList.add(s.getSymbol().trim() + "," + s.getCompany().trim()
+ + "," + s.getSalesPrice().toString())
+ );
+ return stringList;
+ }
+}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/FileParser.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/FileParser.java
new file mode 100644
index 0000000..d0d0279
--- /dev/null
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/FileParser.java
@@ -0,0 +1,184 @@
+package edu.ntnu.idi.idatt2003.g40.mappe;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.List;
+import java.util.function.Predicate;
+
+/**
+ * Class used to parse (filter) valid stocks from a .txt file.
+ *
+ * Responsibilities:
+ *
+ * - Read file and return a filtered list of string elements,
+ * where each element represents a valid stock line.
+ *
+ * - Write a list of string representations of stock objects
+ * to file, each stock separated by a line.
+ *
+ *
+ * Used with {@link FileConverter}
+ *
+ * @see FileConverter
+ * @author tohja
+ * @version 1.0.0
+ * */
+public class FileParser {
+
+ /** The path name this parser is using.*/
+ private final String pathName;
+
+ /**
+ * Rule set for validating lines and strings.
+ *
+ * Uses predicates.
+ * */
+ private enum ParserRuleSet {
+
+ /**
+ * Rule for whether string is empty or not.
+ * */
+ NOT_EMPTY(s -> !s.trim().isEmpty()),
+
+ /**
+ * Rule for if string is comment or not.
+ * */
+ NOT_COMMENT(s -> !s.startsWith("#")),
+
+ /**
+ * Rule for if line is in valid format.
+ * */
+ VALID_FORMAT(NOT_EMPTY.rule.and(NOT_COMMENT.rule)),
+
+ /**
+ * Rule for if string is considered a valid company symbol.
+ * */
+ VALID_CODE(s -> s.matches("[A-Z]{4}")),
+
+ /**
+ * Rule for if string is a valid company name.
+ * */
+ VALID_NAME(s -> s.matches(".*")),
+
+ /**
+ * Rule for if string can be parsed to a {@link BigDecimal} object.
+ * */
+ CAN_PARSE_TO_BIG_DECIMAL(s -> {
+ try {
+ new BigDecimal(s);
+ return true;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }),
+
+ /**
+ * Rule for if string is in a valid price format.
+ * */
+ VALID_PRICE_FORMAT(s -> s.matches("[^a-zA-Z]+")),
+
+ /**
+ * Rule for if string is a valid price.
+ * */
+ VALID_PRICE(VALID_PRICE_FORMAT.rule.and(CAN_PARSE_TO_BIG_DECIMAL.rule));
+
+ /**
+ * The constants' rules as predicates with input of type string.
+ * */
+ private final Predicate rule;
+
+ ParserRuleSet(final Predicate rule) {
+ this.rule = rule;
+ }
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param pathName the file path name to read.
+ * */
+ public FileParser(final String pathName) {
+ this.pathName = pathName;
+ }
+
+ /**
+ * Reads the file and returns a list element of all valid stocks as strings.
+ *
+ * Uses {@link BufferedReader} for opening a file stream.
+ *
+ * @return {@link List} object of all valid stock strings in file.
+ *
+ * @throws IOException if path cannot be read.
+ *
+ * @see Path
+ * */
+
+ public List readFile() throws IOException {
+ Path path = Paths.get(pathName);
+ try (BufferedReader bufferedReader = Files.newBufferedReader(path)) {
+
+ List allLines = bufferedReader.readAllLines();
+ List readableLines =
+ allLines.stream()
+ .filter(ParserRuleSet.VALID_FORMAT.rule).toList();
+
+ // Valid lines (following the correct regular expressions)
+ return readableLines.stream().filter(s -> {
+ String[] parts = s.trim().split(",");
+
+ if (parts.length != 3) {
+ return false;
+ }
+
+ boolean validCode = ParserRuleSet
+ .VALID_CODE.rule.test(parts[0].trim());
+
+ boolean validName = ParserRuleSet
+ .VALID_NAME.rule.test(parts[1].trim());
+
+ boolean validPrice = ParserRuleSet
+ .VALID_PRICE.rule.test(parts[2].trim());
+
+ return validCode && validName && validPrice;
+ }).toList();
+
+ } catch (IOException e) {
+ throw new IOException("File parser could not parse file!");
+ }
+ }
+
+ /**
+ * Writes a given lists of stocks to the file.
+ *
+ * Uses {@link BufferedWriter}.
+ *
+ * @param stringList list of strings representing stocks in the format
+ * SYMBOL, NAME, PRICE
+ *
+ * @throws IOException if writing process throws error.
+ * */
+ public void writeStocksToFile(final List stringList)
+ throws IOException {
+ Path path = Paths.get(pathName);
+
+ try (BufferedWriter writer = Files.newBufferedWriter(path,
+ StandardOpenOption.CREATE,
+ StandardOpenOption.APPEND)) {
+
+ writer.newLine();
+
+ for (String line : stringList) {
+ writer.write(line);
+ writer.newLine();
+ }
+ } catch (IOException e) {
+ throw new IOException("Error during buffered write", e);
+ }
+ }
+}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java
index b835759..186a1ba 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java
@@ -1,17 +1,18 @@
package edu.ntnu.idi.idatt2003.g40.mappe;
-//TIP To Run code, press or
-// click the icon in the gutter.
+import java.io.IOException;
+import java.util.List;
+
public class Main {
static void main() {
- //TIP Press with your caret at the highlighted text
- // to see how IntelliJ IDEA suggests fixing it.
- IO.println(String.format("Hello and welcome!"));
-
- for (int i = 1; i <= 5; i++) {
- //TIP Press to start debugging your code. We have set one breakpoint
- // for you, but you can always add more by pressing .
- IO.println("i = " + i);
+ FileParser parser1 = new FileParser("src/main/resources/dummydata.txt");
+ FileConverter converter1 = new FileConverter();
+ try {
+ List stocksInFile = converter1.getStocksFromStrings(parser1.readFile());
+ parser1.writeStocksToFile(converter1.stocksToStrings(stocksInFile));
+ stocksInFile.forEach(s -> System.out.println(s.getSymbol()));
+ } catch (IOException e) {
+ System.err.println(e.getMessage());
}
}
}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Stock.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Stock.java
index 6f433a1..9e44c68 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Stock.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Stock.java
@@ -1,5 +1,6 @@
package edu.ntnu.idi.idatt2003.g40.mappe;
+import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
@@ -50,7 +51,7 @@ public Stock(final String symbol,
*
* @return the stock symbol
*/
- public String getSymbol() {
+ public String getSymbol() {
return symbol;
}
@@ -129,5 +130,4 @@ public BigDecimal getLatestPriceChange() {
return currentPrice.subtract(previousPrice);
}
-
}
diff --git a/src/main/resources/dummydata.txt b/src/main/resources/dummydata.txt
new file mode 100644
index 0000000..25144a3
--- /dev/null
+++ b/src/main/resources/dummydata.txt
@@ -0,0 +1,14 @@
+#THIS IS A COMMENT.
+
+AAPL, Apple Inc., 276.43
+NVID, Nvidida Corporation, 241.591
+
+#Above me are some valid formats.
+#Below me are some invalid formats
+
+COOLI, This is a cool name, 252.2
+
+COOL, This is a cool name, 252.2a
+
+AAPL,Apple Inc.,276.43
+NVID,Nvidida Corporation,241.591
\ No newline at end of file
diff --git a/src/main/resources/testStockData.txt b/src/main/resources/testStockData.txt
new file mode 100644
index 0000000..b349d0e
--- /dev/null
+++ b/src/main/resources/testStockData.txt
@@ -0,0 +1,11 @@
+#THIS IS A COMMENT.
+
+AAPL, Apple Inc., 276.43
+NVID, Nvidida Corporation, 241.591
+
+#Above me are some valid formats.
+#Below me are some invalid formats
+
+COOLI, This is a cool name, 252.2
+
+COOL, This is a cool name, 252.2a
\ No newline at end of file
diff --git a/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/FileConverterTest.java b/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/FileConverterTest.java
new file mode 100644
index 0000000..6404d78
--- /dev/null
+++ b/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/FileConverterTest.java
@@ -0,0 +1,74 @@
+package edu.ntnu.idi.idatt2003.g40.mappe;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class FileConverterTest {
+
+ private FileConverter converter;
+
+ private String validStockAsString1;
+ private String validStockAsString2;
+ private String validStockAsString3;
+ private ArrayList allStocks;
+ private String invalidStockAsString1;
+
+ @BeforeEach
+ void setUp() {
+ validStockAsString1 = "AAPL, Apple inc., 251.42";
+ validStockAsString2 = "NVID, Nvidia corp., 100.25";
+ validStockAsString3 = "SAMS, Samsung corporation, 103.21";
+
+ invalidStockAsString1 = "INVALID, This stock has an invalid code!, 100.21";
+
+ allStocks = new ArrayList<>();
+
+ allStocks.add(validStockAsString1);
+ allStocks.add(validStockAsString2);
+ allStocks.add(validStockAsString3);
+ allStocks.add(invalidStockAsString1);
+
+ converter = new FileConverter();
+ }
+
+ @Test
+ void converter_returns_valid_stock_apple() {
+
+ boolean stockIncluded = false;
+
+ List stocksFromConverter = converter.getStocksFromStrings(allStocks);
+
+ for (Stock s : stocksFromConverter) {
+ if (s.getSymbol().equals("AAPL")) {
+ stockIncluded = true;
+ break;
+ }
+ }
+
+ Assertions.assertTrue(stockIncluded);
+ }
+
+ @Test
+ void converter_ignores_invalid_stock_representation() {
+
+ boolean stockIncluded = false;
+
+ List stocksFromConverter = converter.getStocksFromStrings(allStocks);
+
+ for (Stock s : stocksFromConverter) {
+ if (s.getSymbol().equals("INVALID")) {
+ stockIncluded = true;
+ break;
+ }
+ }
+
+ Assertions.assertFalse(stockIncluded);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/FileParserTest.java b/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/FileParserTest.java
new file mode 100644
index 0000000..2935a30
--- /dev/null
+++ b/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/FileParserTest.java
@@ -0,0 +1,60 @@
+package edu.ntnu.idi.idatt2003.g40.mappe;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class FileParserTest {
+
+ private final String testStockDataPath = "src/main/resources/testStockData.txt";
+ FileParser fileParser;
+
+ private final String validStockFromFile = "NVID, Nvidida Corporation, 241.591";
+
+ private final String invalidStockFromFile = "COOLI, This is a cool name, 252.2";
+
+ private final String commentFromFile = "#Above me are some valid formats.";
+
+ private List allLines = new ArrayList<>();
+
+ private List validStocks = new ArrayList<>();
+
+ @BeforeEach
+ void setUp() throws Exception {
+ fileParser = new FileParser(testStockDataPath);
+ Path path = Paths.get(testStockDataPath);
+ allLines = Files.readAllLines(path);
+ try {
+ validStocks = fileParser.readFile();
+ } catch (Exception _) {
+ throw new Exception("Test failed");
+ }
+ }
+
+ @Test
+ void parser_gets_valid_stock_from_file() {
+ assertTrue(allLines.contains(validStockFromFile));
+ assertTrue(validStocks.contains(validStockFromFile));
+ }
+
+ @Test
+ void parser_skips_comments_from_file() {
+ assertTrue(allLines.contains(commentFromFile));
+ assertFalse(validStocks.contains(commentFromFile));
+ }
+
+ @Test
+ void parser_skips_invalid_stock_from_file() {
+ assertTrue(allLines.contains(invalidStockFromFile));
+ assertFalse(validStocks.contains(invalidStockFromFile));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/StockTest.java b/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/StockTest.java
index 1aaa672..9fa9f1a 100644
--- a/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/StockTest.java
+++ b/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/StockTest.java
@@ -74,7 +74,6 @@ void getHistoricalPricesGetsAllPrices() {
boolean historicalPricesContainBothValues = historicalPrices.contains(new BigDecimal("100.00"))
&& historicalPrices.contains(new BigDecimal("200.00"));
-
assertTrue(historicalPricesContainBothValues);
}
diff --git a/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/TransactionTest.java b/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/TransactionTest.java
deleted file mode 100644
index bc0b909..0000000
--- a/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/TransactionTest.java
+++ /dev/null
@@ -1,3 +0,0 @@
-public class TransactionTest {
-
-}