From 1dc26cb8d0ec7a7baf05a53cc90a352cf12bb96f Mon Sep 17 00:00:00 2001
From: =
Date: Mon, 11 May 2026 12:52:58 +0200
Subject: [PATCH 01/12] Feat: Added validation enum and validation for multiple
classes
---
.../idatt2003/g40/mappe/engine/Exchange.java | 34 +++++-
.../idi/idatt2003/g40/mappe/model/Player.java | 25 +++-
.../idatt2003/g40/mappe/model/Portfolio.java | 38 ++++--
.../idi/idatt2003/g40/mappe/model/Share.java | 7 +-
.../idi/idatt2003/g40/mappe/model/Stock.java | 28 +++--
.../g40/mappe/model/Transaction.java | 15 ++-
.../g40/mappe/service/FileConverter.java | 64 ++++++----
.../g40/mappe/service/FileParser.java | 26 ++--
.../g40/mappe/service/PurchaseCalculator.java | 16 ++-
.../g40/mappe/service/SaleCalculator.java | 15 ++-
.../idatt2003/g40/mappe/utils/Validator.java | 115 ++++++++++++++++++
.../idatt2003/g40/mappe/view/ViewData.java | 11 +-
.../idatt2003/g40/mappe/view/ViewElement.java | 48 ++++----
.../idatt2003/g40/mappe/view/ViewManager.java | 87 +++++++++----
.../idatt2003/g40/mappe/model/StockTest.java | 32 +----
15 files changed, 402 insertions(+), 159 deletions(-)
create mode 100644 src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/utils/Validator.java
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/Exchange.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/Exchange.java
index 6d5b004..8eec48d 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/Exchange.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/Exchange.java
@@ -1,14 +1,15 @@
package edu.ntnu.idi.idatt2003.g40.mappe.engine;
+import edu.ntnu.idi.idatt2003.g40.mappe.model.Player;
import edu.ntnu.idi.idatt2003.g40.mappe.model.Purchase;
import edu.ntnu.idi.idatt2003.g40.mappe.model.Sale;
import edu.ntnu.idi.idatt2003.g40.mappe.model.Share;
-import edu.ntnu.idi.idatt2003.g40.mappe.model.Player;
import edu.ntnu.idi.idatt2003.g40.mappe.model.Stock;
import edu.ntnu.idi.idatt2003.g40.mappe.model.Transaction;
import edu.ntnu.idi.idatt2003.g40.mappe.service.PurchaseCalculator;
import edu.ntnu.idi.idatt2003.g40.mappe.service.SaleCalculator;
import edu.ntnu.idi.idatt2003.g40.mappe.service.TransactionCalculator;
+import edu.ntnu.idi.idatt2003.g40.mappe.utils.Validator;
import java.math.BigDecimal;
import java.util.ArrayList;
@@ -56,13 +57,17 @@ public final class Exchange {
*
* @param name name of exchange.
* @param stocks list of {@link Stock} objects.
+ *
+ * @throws IllegalArgumentException if name or stocks are empty/null.
* */
- public Exchange(final String name, final List stocks) {
+ public Exchange(final String name, final List stocks) throws IllegalArgumentException {
+ if (!Validator.NOT_EMPTY.isValid(name) || stocks == null || stocks.isEmpty()) {
+ throw new IllegalArgumentException("Invalid exchange parameters!");
+ }
this.name = name;
this.week = 1;
this.stockMap = new HashMap<>();
this.random = new Random();
-
for (Stock stock : stocks) {
stockMap.put(stock.getSymbol(), stock);
}
@@ -103,8 +108,14 @@ public boolean hasStock(final String symbol) {
* @param symbol the symbol of the stock to get.
*
* @return {@link Stock} element gotten.
+ *
+ * @throws IllegalArgumentException if symbol is invalid.
* */
- public Stock getStock(final String symbol) {
+ public Stock getStock(final String symbol) throws IllegalArgumentException {
+ if (!Validator.VALID_STOCK_NAME.isValid(symbol)) {
+ throw new IllegalArgumentException(
+ Validator.VALID_STOCK_NAME.getErrorMessage());
+ }
return stockMap.get(symbol);
}
@@ -136,10 +147,15 @@ public List findStocks(final String searchTerm) {
* @param player the player buying stock.
*
* @return Transaction representing the transaction.
+ *
+ * @throws IllegalArgumentException if symbol or player is invalid.
* */
public Transaction buy(final String symbol,
final BigDecimal quantity,
- final Player player) {
+ final Player player) throws IllegalArgumentException {
+ if (!Validator.VALID_STOCK_NAME.isValid(symbol) || player == null) {
+ throw new IllegalArgumentException("Invalid purchase!");
+ }
Stock stock = stockMap.get(symbol);
Share share = new Share(stock, quantity, stock.getSalesPrice());
TransactionCalculator calculator = new PurchaseCalculator(share);
@@ -154,8 +170,14 @@ public Transaction buy(final String symbol,
* @param player the player buying stock.
*
* @return Transaction representing the transaction.
+ *
+ * @throws IllegalArgumentException if share or player is null.
* */
- public Transaction sell(final Share share, final Player player) {
+ public Transaction sell(final Share share, final Player player)
+ throws IllegalArgumentException {
+ if (share == null || player == null) {
+ throw new IllegalArgumentException("Invalid sell!");
+ }
TransactionCalculator calculator = new SaleCalculator(share);
player.addMoney(calculator.calculateTotal());
return new Sale(share, week, calculator);
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Player.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Player.java
index 8b997ce..971313e 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Player.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Player.java
@@ -1,8 +1,8 @@
package edu.ntnu.idi.idatt2003.g40.mappe.model;
-import edu.ntnu.idi.idatt2003.g40.mappe.engine.Exchange;
+import edu.ntnu.idi.idatt2003.g40.mappe.controller.PlayerStatusController;
import edu.ntnu.idi.idatt2003.g40.mappe.engine.TransactionArchive;
-
+import edu.ntnu.idi.idatt2003.g40.mappe.utils.Validator;
import java.math.BigDecimal;
/**
@@ -11,7 +11,8 @@
*
Each player:
*
*
Has a portfolio
- *
Can buy and sell shares on an {@link Exchange}
+ *
Can buy and sell shares on an
+ * {@link edu.ntnu.idi.idatt2003.g40.mappe.engine.Exchange}.
*
Has a set amount of money to use on said exchange.
*
Has a {@link TransactionArchive}
*
@@ -49,8 +50,13 @@ public final class Player {
*
* @param name the name of the player
* @param startingMoney the starting amount of money
+ *
+ * @throws IllegalArgumentException if name is null.
*/
- public Player(final String name, final BigDecimal startingMoney) {
+ public Player(final String name, final BigDecimal startingMoney) throws IllegalArgumentException {
+ if (!Validator.NOT_EMPTY.isValid(name)) {
+ throw new IllegalArgumentException("Invalid name!");
+ }
this.name = name;
this.startingMoney = startingMoney;
this.money = this.startingMoney;
@@ -132,4 +138,15 @@ public BigDecimal getNetWorth() {
netWorth = netWorth.add(portfolio.getNetWorth()).add(money);
return netWorth;
}
+
+ /**
+ * Getter method for players' current status.
+ *
+ *
Leaves calculations for the {@link PlayerStatusController}
+ *
+ * @return PlayerStatus.
+ * */
+ public PlayerStatus getStatus() {
+ return PlayerStatusController.getStatus(this);
+ }
}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Portfolio.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Portfolio.java
index 305a7e1..756dc96 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Portfolio.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Portfolio.java
@@ -1,6 +1,7 @@
package edu.ntnu.idi.idatt2003.g40.mappe.model;
import edu.ntnu.idi.idatt2003.g40.mappe.service.SaleCalculator;
+import edu.ntnu.idi.idatt2003.g40.mappe.utils.Validator;
import java.math.BigDecimal;
import java.util.ArrayList;
@@ -31,10 +32,15 @@ public Portfolio() {
* Adds a share to the portfolio.
*
* @param share the share to add
+ *
* @return {@code true} if the share was added, {@code false} otherwise
+ *
+ * @throws IllegalArgumentException if share is null.
*/
- public boolean addShare(final Share share) {
- Objects.requireNonNull(share, "share cannot be null");
+ public boolean addShare(final Share share) throws IllegalArgumentException {
+ if (share == null) {
+ throw new IllegalArgumentException("Invalid share!");
+ }
return shares.add(share);
}
@@ -42,11 +48,17 @@ public boolean addShare(final Share share) {
* Removes a share from the portfolio.
*
* @param share the share to remove
+ *
* @return {@code true} if the share was removed,
* {@code false} if it was not present.
+ *
+ * @throws IllegalArgumentException if share is null.
+ *
*/
- public boolean removeShare(final Share share) {
- Objects.requireNonNull(share, "share cannot be null");
+ public boolean removeShare(final Share share) throws IllegalArgumentException {
+ if (share == null) {
+ throw new IllegalArgumentException("Invalid share!");
+ }
return shares.remove(share);
}
@@ -65,9 +77,14 @@ public List getShares() {
*
* @param symbol the stock symbol to match
* @return a list of shares matching the symbol
+ *
+ * @throws IllegalArgumentException if symbol is invalid.
*/
- public List getShares(final String symbol) {
- Objects.requireNonNull(symbol, "symbol cannot be null");
+ public List getShares(final String symbol) throws IllegalArgumentException {
+ if (!Validator.VALID_STOCK_NAME.isValid(symbol)) {
+ throw new IllegalArgumentException(
+ Validator.VALID_STOCK_NAME.getErrorMessage());
+ }
return shares.stream()
.filter(s -> symbol.equalsIgnoreCase(s.getStock().getSymbol()))
.toList();
@@ -77,11 +94,16 @@ public List getShares(final String symbol) {
* Checks whether the given share exists in the portfolio.
*
* @param share the share to check
+ *
* @return {@code true} if the portfolio
* contains the share, otherwise {@code false}
+ *
+ * @throws IllegalArgumentException if share is null.
*/
- public boolean contains(final Share share) {
- Objects.requireNonNull(share, "share cannot be null");
+ public boolean contains(final Share share) throws IllegalArgumentException {
+ if (share == null) {
+ throw new IllegalArgumentException("Invalid share!");
+ }
return shares.contains(share);
}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Share.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Share.java
index 88e51eb..3328a74 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Share.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Share.java
@@ -31,10 +31,15 @@ public final class Share {
* @param stock the stock that was purchased
* @param quantity the quantity purchased
* @param purchasePrice the price per unit at purchase time
+ *
+ * @throws IllegalArgumentException if stock is null.
*/
public Share(final Stock stock,
final BigDecimal quantity,
- final BigDecimal purchasePrice) {
+ final BigDecimal purchasePrice) throws IllegalArgumentException {
+ if (stock == null) {
+ throw new IllegalArgumentException("Invalid stock!");
+ }
this.stock = stock;
this.quantity = quantity;
this.purchasePrice = purchasePrice;
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Stock.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Stock.java
index a781ee4..11a444e 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Stock.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Stock.java
@@ -1,5 +1,6 @@
package edu.ntnu.idi.idatt2003.g40.mappe.model;
+import edu.ntnu.idi.idatt2003.g40.mappe.utils.Validator;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
@@ -34,15 +35,15 @@ public final class Stock {
*/
public Stock(final String symbol,
final String company,
- final BigDecimal salesPrice) {
-
- if (symbol.length() != 4) {
+ final BigDecimal salesPrice) throws IllegalArgumentException {
+ if (!Validator.VALID_STOCK_NAME.isValid(symbol)) {
throw new IllegalArgumentException(
- "Stock's symbol must be 4 characters!");
+ Validator.VALID_STOCK_NAME.getErrorMessage());
+ } else {
+ this.symbol = symbol;
+ this.company = company;
+ prices.add(salesPrice);
}
- this.symbol = symbol;
- this.company = company;
- prices.add(salesPrice);
}
/**
@@ -50,7 +51,7 @@ public Stock(final String symbol,
*
* @return the stock symbol
*/
- public String getSymbol() {
+ public String getSymbol() {
return symbol;
}
@@ -76,9 +77,16 @@ public BigDecimal getSalesPrice() {
* Adds a new sales price to the price history.
*
* @param price the new sales price
+ *
+ * @throws IllegalArgumentException if price is 0 or null.
*/
- public void addNewSalesPrice(final BigDecimal price) {
- prices.add(price);
+ public void addNewSalesPrice(final BigDecimal price)
+ throws IllegalArgumentException {
+ if (price != null && price.intValue() != 0) {
+ prices.add(price);
+ } else {
+ throw new IllegalArgumentException("Invalid price to add to stock: " + getSymbol());
+ }
}
/**
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Transaction.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Transaction.java
index f0b210d..fe7e6c5 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Transaction.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Transaction.java
@@ -34,13 +34,20 @@ public abstract class Transaction {
* @param share the share to perform the transaction on
* @param week the current week to perform the transaction under
* @param calculator the {@link TransactionCalculator} to use.
+ *
+ * @throws IllegalArgumentException if any parameter is null.
*/
protected Transaction(final Share share, final int week,
- final TransactionCalculator calculator) {
- this.share = share;
- this.week = week;
- this.calculator = calculator;
+ final TransactionCalculator calculator)
+ throws IllegalArgumentException{
+ if (share == null || calculator == null) {
+ throw new IllegalArgumentException("Invalid stock or calculator!");
+ } else {
+ this.share = share;
+ this.week = week;
+ this.calculator = calculator;
+ }
}
/**
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/FileConverter.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/FileConverter.java
index 9a479ec..397328d 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/FileConverter.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/FileConverter.java
@@ -1,7 +1,6 @@
package edu.ntnu.idi.idatt2003.g40.mappe.service;
import edu.ntnu.idi.idatt2003.g40.mappe.model.Stock;
-
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
@@ -35,32 +34,37 @@ public class FileConverter {
*
* @return {@link List}
*
- * @throws IllegalArgumentException if stock object(s) cannot be converted.
+ * @throws IllegalArgumentException if stock object(s) cannot be converted,
+ * or if list is null/empty.
*
* */
- public List getStocksFromStrings(final List validStocks) {
-
- List stocksFromFile = new ArrayList<>();
- List stockSymbols = new ArrayList<>();
+ public List getStocksFromStrings(final List validStocks)
+ throws IllegalArgumentException {
+ if (validStocks == null || validStocks.isEmpty()) {
+ throw new IllegalArgumentException("Empty or null stock list!");
+ } else {
+ List stocksFromFile = new ArrayList<>();
+ List 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());
+ 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);
+ 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...");
}
- } catch (IllegalArgumentException e) {
- System.err.println("(" + s + ") is not a valid stock! Skipping...");
- }
- });
- return stocksFromFile;
+ });
+ return stocksFromFile;
+ }
}
/**
@@ -71,13 +75,19 @@ public List getStocksFromStrings(final List validStocks) {
* @param stocks a list of {@link Stock} objects.
*
* @return a list of string representation of the stock objects.
+ *
+ * @throws IllegalArgumentException if stocks is empty or null.
* */
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;
+ if (stocks == null || stocks.isEmpty()) {
+ throw new IllegalArgumentException("Empty or null stock list!");
+ } else {
+ 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/service/FileParser.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/FileParser.java
index 155d36d..9d0bf27 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/FileParser.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/FileParser.java
@@ -164,21 +164,25 @@ public List readFile() throws IOException {
* @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)) {
+ throws IllegalArgumentException, IOException {
+ if (stringList == null || stringList.isEmpty()) {
+ throw new IllegalArgumentException("Empty or null list of stocks!");
+ } else {
+ Path path = Paths.get(pathName);
- writer.newLine();
+ try (BufferedWriter writer = Files.newBufferedWriter(path,
+ StandardOpenOption.CREATE,
+ StandardOpenOption.APPEND)) {
- for (String line : stringList) {
- writer.write(line);
writer.newLine();
+
+ for (String line : stringList) {
+ writer.write(line);
+ writer.newLine();
+ }
+ } catch (IOException e) {
+ throw new IOException("Error during buffered write", e);
}
- } catch (IOException e) {
- throw new IOException("Error during buffered write", e);
}
}
}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/PurchaseCalculator.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/PurchaseCalculator.java
index 49ce7c1..e253dd3 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/PurchaseCalculator.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/PurchaseCalculator.java
@@ -1,7 +1,6 @@
package edu.ntnu.idi.idatt2003.g40.mappe.service;
import edu.ntnu.idi.idatt2003.g40.mappe.model.Share;
-
import java.math.BigDecimal;
/**
@@ -32,10 +31,19 @@ public final class PurchaseCalculator implements TransactionCalculator {
* Creates a new {@code PurchaseCalculator} based on a share.
*
* @param share the share to base calculations on
+ *
+ * @throws IllegalArgumentException if share is null.
*/
- public PurchaseCalculator(final Share share) {
- this.purchasePrice = share.getPurchasePrice();
- this.quantity = share.getQuantity();
+ public PurchaseCalculator(final Share share) throws IllegalArgumentException {
+ if (share == null) {
+ throw new IllegalArgumentException(
+ "Invalid share for PurchaseCalculator!"
+ );
+ } else {
+ this.purchasePrice = share.getPurchasePrice();
+ this.quantity = share.getQuantity();
+ }
+
}
/**
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/SaleCalculator.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/SaleCalculator.java
index 0cba5dc..1c2a0bb 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/SaleCalculator.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/SaleCalculator.java
@@ -1,7 +1,6 @@
package edu.ntnu.idi.idatt2003.g40.mappe.service;
import edu.ntnu.idi.idatt2003.g40.mappe.model.Share;
-
import java.math.BigDecimal;
/**
@@ -43,11 +42,17 @@ public final class SaleCalculator implements TransactionCalculator {
* Creates a new {@code SaleCalculator} based on a share.
*
* @param share the share to base calculations on
+ *
+ * @throws IllegalArgumentException if share is null.
*/
- public SaleCalculator(final Share share) {
- this.purchasePrice = share.getPurchasePrice();
- this.salesPrice = share.getStock().getSalesPrice();
- this.quantity = share.getQuantity();
+ public SaleCalculator(final Share share) throws IllegalArgumentException {
+ if (share == null) {
+ throw new IllegalArgumentException("Invalid share for SaleCalculator!");
+ } else {
+ this.purchasePrice = share.getPurchasePrice();
+ this.salesPrice = share.getStock().getSalesPrice();
+ this.quantity = share.getQuantity();
+ }
}
/**
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/utils/Validator.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/utils/Validator.java
new file mode 100644
index 0000000..6d12cbc
--- /dev/null
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/utils/Validator.java
@@ -0,0 +1,115 @@
+package edu.ntnu.idi.idatt2003.g40.mappe.utils;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeParseException;
+import java.util.function.Predicate;
+
+/**
+ * Enum containing rules for different types of validation.
+ *
+ *
Validates by using {@link Predicate}
+ *
+ *
Every constant has the following attributes:
+ *
+ *
A rule for a specific validation, defined by a {@link Predicate}.
+ *
+ * An error message to be used if input is invalid according to the rule.
+ *
+ *
+ *
+ *
Responsibilities:
+ *
+ *
+ * Checking whether given string is
+ * valid based on the given validation rule.
+ *
+ *
+ *
+ * @author Tohja
+ * @version 1.0.0
+ *
+ * @see Enum
+ * @see Predicate
+ */
+public enum Validator {
+
+ /**
+ * Rule that checks if string is not empty.
+ * */
+ NOT_EMPTY(s -> s != null && !s.trim().isEmpty(),
+ "Empty string!"),
+
+ /**
+ * Rule that checks if string is not empty,
+ * and if it can be parsed into an {@link Integer}.
+ */
+ VALID_INT(NOT_EMPTY.validationRule.and(s -> {
+ try {
+ Integer.parseInt(s);
+ return true;
+ } catch (NumberFormatException _) {
+ return false;
+ }
+ }), "Invalid Integer!"),
+
+ /**
+ * Rule that checks if a string is considered a valid stock name.
+ * */
+ VALID_STOCK_NAME(NOT_EMPTY.validationRule.and(s ->
+ s.length() == 4), "Invalid stock name!"),
+
+ /**
+ * Rule that checks if a string represents a positive integer.
+ * */
+ VALID_POSITIVE_INT(VALID_INT.validationRule.and(s ->
+ Integer.parseInt(s) >= 0), "Number is not positive!"),
+ /**
+ * Rule that checks if string is not empty,
+ * and if it can be parsed into a {@link LocalDate} object.
+ */
+ VALID_DATE(NOT_EMPTY.validationRule.and(s -> {
+ try {
+ LocalDate.parse(s);
+ return true;
+ } catch (DateTimeParseException e) {
+ return false;
+ }
+ }), "Invalid Date!");
+
+ /** The predicate field set when creating constants. */
+ private final Predicate validationRule;
+
+ /** The error message field set when creating constants. */
+ private final String errorMessage;
+
+ /**
+ * Constructor.
+ *
+ * @param validationRule the {@link Predicate} object to set as rule.
+ * @param errorMessage the message to use on invalid input.
+ */
+ Validator(final Predicate validationRule, final String errorMessage) {
+ this.validationRule = validationRule;
+ this.errorMessage = errorMessage;
+ }
+
+ /**
+ * Method used to validate a given string by the given constant.
+ *
+ * @param input the input string to validate.
+ *
+ * @return {@link Boolean} value, true if input is valid, false otherwise.
+ */
+ public boolean isValid(final String input) {
+ return validationRule.test(input);
+ }
+
+ /**
+ * Method used to get the error message of the given constant.
+ *
+ * @return the error message.
+ */
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ViewData.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ViewData.java
index 06dbdfc..33fca3c 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ViewData.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ViewData.java
@@ -1,5 +1,7 @@
package edu.ntnu.idi.idatt2003.g40.mappe.view;
+import edu.ntnu.idi.idatt2003.g40.mappe.utils.Validator;
+
/**
* Object containing data about {@link ViewElement} objects.
*
@@ -22,9 +24,14 @@ public class ViewData {
*
* @param sceneName the name of the scene.
*
+ * @throws IllegalArgumentException if sceneName is empty or null.
*/
- public ViewData(final String sceneName) {
- this.sceneName = sceneName;
+ public ViewData(final String sceneName) throws IllegalArgumentException {
+ if (Validator.NOT_EMPTY.isValid(sceneName)) {
+ this.sceneName = sceneName;
+ } else {
+ throw new IllegalArgumentException(Validator.NOT_EMPTY.getErrorMessage());
+ }
}
/**
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ViewElement.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ViewElement.java
index fec4af4..554ccfc 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ViewElement.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ViewElement.java
@@ -1,12 +1,13 @@
package edu.ntnu.idi.idatt2003.g40.mappe.view;
-
+import edu.ntnu.idi.idatt2003.g40.mappe.utils.Validator;
+import java.util.ArrayList;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
-import java.util.ArrayList;
/**
- * Base class for view elements, such as the main menu, or list items.
+ * Base class for view elements, such as the main menu,
+ * or navigation bars used across several views.
*
*
Extends {@link Pane}
*
@@ -20,6 +21,7 @@ public abstract class ViewElement {
*
*/
private final ArrayList
*
* @param data the id of the {@link ViewElement} to change the scene to.
+ *
+ * @throws IllegalArgumentException if data is null.
+ *
* @see EventSubscriber
* @see EventData
*/
- public void setScene(final ViewData data) {
- ViewElement> viewElement = viewMap.get(data.getSceneName());
- viewElement.setData(data);
- stage.getScene().setRoot(viewElement.getRootPane());
- currentView = viewElement;
- currentView.onUpdate();
+ public void setScene(final ViewData data) throws IllegalArgumentException {
+ if (data == null) {
+ throw new IllegalArgumentException("Data is null!");
+ } else {
+ ViewElement> viewElement = viewMap.get(data.getSceneName());
+ viewElement.setData(data);
+ setScene(viewElement);
+ currentView = viewElement;
+ }
}
/**
@@ -108,7 +148,6 @@ public ViewElement> getCurrentView() {
return currentView;
}
-
/**
* Handles events of type SCENE_CHANGE.
*
@@ -118,10 +157,10 @@ public ViewElement> getCurrentView() {
*/
@Override
public void handleEvent(final EventData data) {
- switch (data.eventType()) {
- case SCENE_CHANGE -> {
- setScene((ViewData) data.data());
- }
+ if (data == null) {
+ throw new IllegalArgumentException("Data is null!");
+ } else {
+ setScene((ViewData) data.data());
}
}
}
diff --git a/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/model/StockTest.java b/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/model/StockTest.java
index c9552c4..c5f907d 100644
--- a/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/model/StockTest.java
+++ b/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/model/StockTest.java
@@ -1,16 +1,13 @@
package edu.ntnu.idi.idatt2003.g40.mappe.model;
-import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
import java.math.BigDecimal;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.*;
+
final class StockTest {
private Stock testStock;
@@ -26,21 +23,6 @@ void constructorSetsSymbolAndCompany() {
assertEquals("Apple Inc.", testStock.getCompany());
}
- /**
- * Tests if getting price throws error on new stock.
- *
- * @deprecated as of part 2.
- * */
- /*
- @Test
- void getSalesPrice_throwsWhenNoPricesExist_currentImplementation() {
- Stock stock = new Stock("AAPL", "Apple Inc.", new BigDecimal("100.00"));
-
- // Because constructor does not add the initial salesPrice to prices,
- // prices is empty and getLast() throws NoSuchElementException.
- assertThrows(NoSuchElementException.class, stock::getSalesPrice);
- }*/
-
@Test
void addNewSalesPriceThenGetSalesPriceReturnsLastAddedPrice() {
testStock.addNewSalesPrice(new BigDecimal("123.45"));
@@ -57,13 +39,11 @@ void addNewSalesPriceTwiceGetSalesPriceReturnsMostRecent() {
}
@Test
- void addNewSalesPriceAllowsNullCurrentImplementation() {
-
- testStock.addNewSalesPrice(null);
+ void addNewSalesPriceDoesNotAllowNullCurrentImplementation() {
- // List allows nulls; getLast returns null -> should not throw.
- assertDoesNotThrow(testStock::getSalesPrice);
- assertNull(testStock.getSalesPrice());
+ assertThrows(IllegalArgumentException.class, () -> {
+ testStock.addNewSalesPrice(null);
+ });
}
@Test
From 589f60a25e0feba51774d70df2bbec3c2b2fcefb Mon Sep 17 00:00:00 2001
From: =
Date: Mon, 11 May 2026 12:53:36 +0200
Subject: [PATCH 02/12] Feat: Added package-info files
---
.../idi/idatt2003/g40/mappe/controller/package-info.java | 6 ++++++
.../ntnu/idi/idatt2003/g40/mappe/engine/package-info.java | 5 +++++
.../ntnu/idi/idatt2003/g40/mappe/model/package-info.java | 5 +++++
.../idi/idatt2003/g40/mappe/service/event/package-info.java | 5 +++++
.../ntnu/idi/idatt2003/g40/mappe/service/package-info.java | 5 +++++
.../ntnu/idi/idatt2003/g40/mappe/utils/package-info.java | 4 ++++
.../edu/ntnu/idi/idatt2003/g40/mappe/view/package-info.java | 6 ++++++
7 files changed, 36 insertions(+)
create mode 100644 src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/controller/package-info.java
create mode 100644 src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/package-info.java
create mode 100644 src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/package-info.java
create mode 100644 src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/package-info.java
create mode 100644 src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/package-info.java
create mode 100644 src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/utils/package-info.java
create mode 100644 src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/package-info.java
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/controller/package-info.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/controller/package-info.java
new file mode 100644
index 0000000..421838f
--- /dev/null
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/controller/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Contains classes that control certain aspects of the application,
+ * such as the
+ * {@link edu.ntnu.idi.idatt2003.g40.mappe.controller.PlayerStatusController}.
+ * */
+package edu.ntnu.idi.idatt2003.g40.mappe.controller;
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/package-info.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/package-info.java
new file mode 100644
index 0000000..70a3863
--- /dev/null
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * Contains classes giving a high level control of the application,
+ * such as {@link edu.ntnu.idi.idatt2003.g40.mappe.engine.Exchange}.
+ * */
+package edu.ntnu.idi.idatt2003.g40.mappe.engine;
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/package-info.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/package-info.java
new file mode 100644
index 0000000..94c2b46
--- /dev/null
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * Contains classes representing data in the application,
+ * such as shares, stocks and transactions.
+ * */
+package edu.ntnu.idi.idatt2003.g40.mappe.model;
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/package-info.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/package-info.java
new file mode 100644
index 0000000..4ad31e6
--- /dev/null
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * Contains classes providing a flexible event system that follows
+ * the publisher/subscriber model.
+ * */
+package edu.ntnu.idi.idatt2003.g40.mappe.service.event;
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/package-info.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/package-info.java
new file mode 100644
index 0000000..633c60a
--- /dev/null
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * Contains classes providing modular functionality to the application,
+ * such as the {@link edu.ntnu.idi.idatt2003.g40.mappe.service.FileConverter}.
+ * */
+package edu.ntnu.idi.idatt2003.g40.mappe.service;
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/utils/package-info.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/utils/package-info.java
new file mode 100644
index 0000000..11c8c6c
--- /dev/null
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/utils/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Package containing utility enums and classes.
+ * */
+package edu.ntnu.idi.idatt2003.g40.mappe.utils;
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/package-info.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/package-info.java
new file mode 100644
index 0000000..46c7655
--- /dev/null
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Contains classes used for displaying views in the javafx framework,
+ * where a view can be considered an arrangement of
+ * UI elements, including their functionality and styling.
+ * */
+package edu.ntnu.idi.idatt2003.g40.mappe.view;
From fe6f10b64fca82ad6a6b7f8c0a5a5145ed24a213 Mon Sep 17 00:00:00 2001
From: =
Date: Mon, 11 May 2026 12:54:56 +0200
Subject: [PATCH 03/12] Feat: Updated playerstatuscontroller and tests
---
.../controller/PlayerStatusController.java | 38 ++++-----------
.../g40/mappe/model/PlayerStatusTest.java | 46 +++++++++++++++----
2 files changed, 46 insertions(+), 38 deletions(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/controller/PlayerStatusController.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/controller/PlayerStatusController.java
index aa45ab6..b69af32 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/controller/PlayerStatusController.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/controller/PlayerStatusController.java
@@ -3,8 +3,6 @@
import edu.ntnu.idi.idatt2003.g40.mappe.model.Player;
import edu.ntnu.idi.idatt2003.g40.mappe.model.PlayerStatus;
-import java.math.BigDecimal;
-
/**
* Controls and calculates the players' status.
*
@@ -20,38 +18,22 @@ private PlayerStatusController() {
*
*
Calculates what status the player should get
* based on players' net worth compared to starting
- * money, and current week.
+ * money.
*
* @param player the player to give a status to.
*
* @return a PlayerStatus
* */
public static PlayerStatus getStatus(final Player player) {
- Integer startingMoneyInt = player.getStartingMoney().intValue();
-
- BigDecimal difference =
- player.getNetWorth().subtract(player.getStartingMoney());
-
- return switch ((Integer) difference.intValue()) {
- case Integer val when val >= percentAmount(startingMoneyInt, 900) -> PlayerStatus.OMNIPOTENT;
- case Integer val when val >= percentAmount(startingMoneyInt, 400) -> PlayerStatus.SEER;
- case Integer val when val >= percentAmount(startingMoneyInt, 200) -> PlayerStatus.PRO;
- case Integer val when val >= percentAmount(startingMoneyInt, 100) -> PlayerStatus.TRYHARD;
- case Integer val when val >= percentAmount(startingMoneyInt, 50) -> PlayerStatus.GOOD;
- case Integer val when val >= percentAmount(startingMoneyInt, 20) -> PlayerStatus.NOVICE;
- default -> PlayerStatus.NOOB;
- };
- }
+ float differenceInPercent = ((player.getNetWorth().floatValue()
+ / player.getStartingMoney().floatValue()) - 1) * 100;
- /**
- * Helper method for increasing a value by x percent.
- *
- * @param value the value to calculate from
- * @param x the percent amount
- *
- * @return the increased value.
- * */
- private static Integer percentAmount(final Integer value, final Integer x) {
- return (value * x) / 100;
+ for (int i = PlayerStatus.values().length; i > 0; i--) {
+ PlayerStatus curStatus = PlayerStatus.values()[i - 1];
+ if (differenceInPercent >= curStatus.getPercentIncreaseNeeded()) {
+ return curStatus;
+ }
+ }
+ return PlayerStatus.NOOB;
}
}
diff --git a/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/model/PlayerStatusTest.java b/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/model/PlayerStatusTest.java
index a9a44f5..1765d46 100644
--- a/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/model/PlayerStatusTest.java
+++ b/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/model/PlayerStatusTest.java
@@ -1,23 +1,49 @@
package edu.ntnu.idi.idatt2003.g40.mappe.model;
-import edu.ntnu.idi.idatt2003.g40.mappe.controller.PlayerStatusController;
-import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import java.math.BigDecimal;
-
-import static org.junit.jupiter.api.Assertions.*;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
class PlayerStatusTest {
+ /**
+ * Player object used for testing.
+ * */
+ private Player testPlayer;
+
+ @BeforeEach
+ void setUp() {
+ testPlayer = new Player("Player", new BigDecimal(1000));
+ }
+
@Test
- void getStatusReturnsProperStatuses() {
- Player testPlayer = new Player("Player", new BigDecimal(1000));
- PlayerStatus gottenStatus = PlayerStatusController.getStatus(testPlayer);
- assertEquals(PlayerStatus.NOOB, gottenStatus);
+ void getStatusAtStartReturnsWorstStatus() {
+ assertEquals(PlayerStatus.NOOB, testPlayer.getStatus());
+ }
+ @Test
+ void getStatusAfterDoubleIncreaseReturnsBetterStatus() {
testPlayer.addMoney(new BigDecimal(1000));
- PlayerStatus gottenStatus2 = PlayerStatusController.getStatus(testPlayer);
+ assertEquals(PlayerStatus.TRYHARD, testPlayer.getStatus());
+ }
+
+ @Test
+ void gettingStatusWhenNegativeDifferenceReturnsWorstStatus() {
+ testPlayer.addMoney(new BigDecimal(-1000));
+ assertEquals(PlayerStatus.NOOB, testPlayer.getStatus());
+ }
+
+ @Test
+ void multipleChangesInValueCauseCorrectStatus() {
+ testPlayer.addMoney(new BigDecimal(2000));
+ assertEquals(PlayerStatus.PRO, testPlayer.getStatus());
+
+ testPlayer.addMoney(new BigDecimal(-1000));
+ assertEquals(PlayerStatus.TRYHARD, testPlayer.getStatus());
- assertEquals(PlayerStatus.TRYHARD, gottenStatus2);
+ testPlayer.addMoney(new BigDecimal(-500));
+ assertEquals(PlayerStatus.GOOD, testPlayer.getStatus());
}
}
\ No newline at end of file
From 1b0c689a6dcf3e9d8d0fe430fb2614df57ef0188 Mon Sep 17 00:00:00 2001
From: =
Date: Mon, 11 May 2026 12:56:20 +0200
Subject: [PATCH 04/12] Revert "Feat: Updated playerstatuscontroller and tests"
This reverts commit fe6f10b64fca82ad6a6b7f8c0a5a5145ed24a213.
---
.../controller/PlayerStatusController.java | 38 +++++++++++----
.../g40/mappe/model/PlayerStatusTest.java | 46 ++++---------------
2 files changed, 38 insertions(+), 46 deletions(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/controller/PlayerStatusController.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/controller/PlayerStatusController.java
index b69af32..aa45ab6 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/controller/PlayerStatusController.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/controller/PlayerStatusController.java
@@ -3,6 +3,8 @@
import edu.ntnu.idi.idatt2003.g40.mappe.model.Player;
import edu.ntnu.idi.idatt2003.g40.mappe.model.PlayerStatus;
+import java.math.BigDecimal;
+
/**
* Controls and calculates the players' status.
*
@@ -18,22 +20,38 @@ private PlayerStatusController() {
*
*
Calculates what status the player should get
* based on players' net worth compared to starting
- * money.
+ * money, and current week.
*
* @param player the player to give a status to.
*
* @return a PlayerStatus
* */
public static PlayerStatus getStatus(final Player player) {
- float differenceInPercent = ((player.getNetWorth().floatValue()
- / player.getStartingMoney().floatValue()) - 1) * 100;
+ Integer startingMoneyInt = player.getStartingMoney().intValue();
+
+ BigDecimal difference =
+ player.getNetWorth().subtract(player.getStartingMoney());
+
+ return switch ((Integer) difference.intValue()) {
+ case Integer val when val >= percentAmount(startingMoneyInt, 900) -> PlayerStatus.OMNIPOTENT;
+ case Integer val when val >= percentAmount(startingMoneyInt, 400) -> PlayerStatus.SEER;
+ case Integer val when val >= percentAmount(startingMoneyInt, 200) -> PlayerStatus.PRO;
+ case Integer val when val >= percentAmount(startingMoneyInt, 100) -> PlayerStatus.TRYHARD;
+ case Integer val when val >= percentAmount(startingMoneyInt, 50) -> PlayerStatus.GOOD;
+ case Integer val when val >= percentAmount(startingMoneyInt, 20) -> PlayerStatus.NOVICE;
+ default -> PlayerStatus.NOOB;
+ };
+ }
- for (int i = PlayerStatus.values().length; i > 0; i--) {
- PlayerStatus curStatus = PlayerStatus.values()[i - 1];
- if (differenceInPercent >= curStatus.getPercentIncreaseNeeded()) {
- return curStatus;
- }
- }
- return PlayerStatus.NOOB;
+ /**
+ * Helper method for increasing a value by x percent.
+ *
+ * @param value the value to calculate from
+ * @param x the percent amount
+ *
+ * @return the increased value.
+ * */
+ private static Integer percentAmount(final Integer value, final Integer x) {
+ return (value * x) / 100;
}
}
diff --git a/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/model/PlayerStatusTest.java b/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/model/PlayerStatusTest.java
index 1765d46..a9a44f5 100644
--- a/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/model/PlayerStatusTest.java
+++ b/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/model/PlayerStatusTest.java
@@ -1,49 +1,23 @@
package edu.ntnu.idi.idatt2003.g40.mappe.model;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-import java.math.BigDecimal;
-import org.junit.jupiter.api.BeforeEach;
+import edu.ntnu.idi.idatt2003.g40.mappe.controller.PlayerStatusController;
import org.junit.jupiter.api.Test;
-class PlayerStatusTest {
+import java.math.BigDecimal;
- /**
- * Player object used for testing.
- * */
- private Player testPlayer;
+import static org.junit.jupiter.api.Assertions.*;
- @BeforeEach
- void setUp() {
- testPlayer = new Player("Player", new BigDecimal(1000));
- }
+class PlayerStatusTest {
@Test
- void getStatusAtStartReturnsWorstStatus() {
- assertEquals(PlayerStatus.NOOB, testPlayer.getStatus());
- }
+ void getStatusReturnsProperStatuses() {
+ Player testPlayer = new Player("Player", new BigDecimal(1000));
+ PlayerStatus gottenStatus = PlayerStatusController.getStatus(testPlayer);
+ assertEquals(PlayerStatus.NOOB, gottenStatus);
- @Test
- void getStatusAfterDoubleIncreaseReturnsBetterStatus() {
testPlayer.addMoney(new BigDecimal(1000));
- assertEquals(PlayerStatus.TRYHARD, testPlayer.getStatus());
- }
-
- @Test
- void gettingStatusWhenNegativeDifferenceReturnsWorstStatus() {
- testPlayer.addMoney(new BigDecimal(-1000));
- assertEquals(PlayerStatus.NOOB, testPlayer.getStatus());
- }
-
- @Test
- void multipleChangesInValueCauseCorrectStatus() {
- testPlayer.addMoney(new BigDecimal(2000));
- assertEquals(PlayerStatus.PRO, testPlayer.getStatus());
-
- testPlayer.addMoney(new BigDecimal(-1000));
- assertEquals(PlayerStatus.TRYHARD, testPlayer.getStatus());
+ PlayerStatus gottenStatus2 = PlayerStatusController.getStatus(testPlayer);
- testPlayer.addMoney(new BigDecimal(-500));
- assertEquals(PlayerStatus.GOOD, testPlayer.getStatus());
+ assertEquals(PlayerStatus.TRYHARD, gottenStatus2);
}
}
\ No newline at end of file
From 1afe967b3b034a3907bd90c5b63bddb501a4c410 Mon Sep 17 00:00:00 2001
From: =
Date: Mon, 11 May 2026 12:56:30 +0200
Subject: [PATCH 05/12] Reapply "Feat: Updated playerstatuscontroller and
tests"
This reverts commit 1b0c689a6dcf3e9d8d0fe430fb2614df57ef0188.
---
.../controller/PlayerStatusController.java | 38 ++++-----------
.../g40/mappe/model/PlayerStatusTest.java | 46 +++++++++++++++----
2 files changed, 46 insertions(+), 38 deletions(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/controller/PlayerStatusController.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/controller/PlayerStatusController.java
index aa45ab6..b69af32 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/controller/PlayerStatusController.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/controller/PlayerStatusController.java
@@ -3,8 +3,6 @@
import edu.ntnu.idi.idatt2003.g40.mappe.model.Player;
import edu.ntnu.idi.idatt2003.g40.mappe.model.PlayerStatus;
-import java.math.BigDecimal;
-
/**
* Controls and calculates the players' status.
*
@@ -20,38 +18,22 @@ private PlayerStatusController() {
*
*
Calculates what status the player should get
* based on players' net worth compared to starting
- * money, and current week.
+ * money.
*
* @param player the player to give a status to.
*
* @return a PlayerStatus
* */
public static PlayerStatus getStatus(final Player player) {
- Integer startingMoneyInt = player.getStartingMoney().intValue();
-
- BigDecimal difference =
- player.getNetWorth().subtract(player.getStartingMoney());
-
- return switch ((Integer) difference.intValue()) {
- case Integer val when val >= percentAmount(startingMoneyInt, 900) -> PlayerStatus.OMNIPOTENT;
- case Integer val when val >= percentAmount(startingMoneyInt, 400) -> PlayerStatus.SEER;
- case Integer val when val >= percentAmount(startingMoneyInt, 200) -> PlayerStatus.PRO;
- case Integer val when val >= percentAmount(startingMoneyInt, 100) -> PlayerStatus.TRYHARD;
- case Integer val when val >= percentAmount(startingMoneyInt, 50) -> PlayerStatus.GOOD;
- case Integer val when val >= percentAmount(startingMoneyInt, 20) -> PlayerStatus.NOVICE;
- default -> PlayerStatus.NOOB;
- };
- }
+ float differenceInPercent = ((player.getNetWorth().floatValue()
+ / player.getStartingMoney().floatValue()) - 1) * 100;
- /**
- * Helper method for increasing a value by x percent.
- *
- * @param value the value to calculate from
- * @param x the percent amount
- *
- * @return the increased value.
- * */
- private static Integer percentAmount(final Integer value, final Integer x) {
- return (value * x) / 100;
+ for (int i = PlayerStatus.values().length; i > 0; i--) {
+ PlayerStatus curStatus = PlayerStatus.values()[i - 1];
+ if (differenceInPercent >= curStatus.getPercentIncreaseNeeded()) {
+ return curStatus;
+ }
+ }
+ return PlayerStatus.NOOB;
}
}
diff --git a/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/model/PlayerStatusTest.java b/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/model/PlayerStatusTest.java
index a9a44f5..1765d46 100644
--- a/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/model/PlayerStatusTest.java
+++ b/src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/model/PlayerStatusTest.java
@@ -1,23 +1,49 @@
package edu.ntnu.idi.idatt2003.g40.mappe.model;
-import edu.ntnu.idi.idatt2003.g40.mappe.controller.PlayerStatusController;
-import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import java.math.BigDecimal;
-
-import static org.junit.jupiter.api.Assertions.*;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
class PlayerStatusTest {
+ /**
+ * Player object used for testing.
+ * */
+ private Player testPlayer;
+
+ @BeforeEach
+ void setUp() {
+ testPlayer = new Player("Player", new BigDecimal(1000));
+ }
+
@Test
- void getStatusReturnsProperStatuses() {
- Player testPlayer = new Player("Player", new BigDecimal(1000));
- PlayerStatus gottenStatus = PlayerStatusController.getStatus(testPlayer);
- assertEquals(PlayerStatus.NOOB, gottenStatus);
+ void getStatusAtStartReturnsWorstStatus() {
+ assertEquals(PlayerStatus.NOOB, testPlayer.getStatus());
+ }
+ @Test
+ void getStatusAfterDoubleIncreaseReturnsBetterStatus() {
testPlayer.addMoney(new BigDecimal(1000));
- PlayerStatus gottenStatus2 = PlayerStatusController.getStatus(testPlayer);
+ assertEquals(PlayerStatus.TRYHARD, testPlayer.getStatus());
+ }
+
+ @Test
+ void gettingStatusWhenNegativeDifferenceReturnsWorstStatus() {
+ testPlayer.addMoney(new BigDecimal(-1000));
+ assertEquals(PlayerStatus.NOOB, testPlayer.getStatus());
+ }
+
+ @Test
+ void multipleChangesInValueCauseCorrectStatus() {
+ testPlayer.addMoney(new BigDecimal(2000));
+ assertEquals(PlayerStatus.PRO, testPlayer.getStatus());
+
+ testPlayer.addMoney(new BigDecimal(-1000));
+ assertEquals(PlayerStatus.TRYHARD, testPlayer.getStatus());
- assertEquals(PlayerStatus.TRYHARD, gottenStatus2);
+ testPlayer.addMoney(new BigDecimal(-500));
+ assertEquals(PlayerStatus.GOOD, testPlayer.getStatus());
}
}
\ No newline at end of file
From 305cfa0d63912f4e926c3aa46551ee5d3896c5a8 Mon Sep 17 00:00:00 2001
From: =
Date: Mon, 11 May 2026 12:57:06 +0200
Subject: [PATCH 06/12] Feat: Updated playerstatus
---
.../g40/mappe/model/PlayerStatus.java | 38 +++++++++++++++----
1 file changed, 31 insertions(+), 7 deletions(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/PlayerStatus.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/PlayerStatus.java
index edd8705..d34c54e 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/PlayerStatus.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/PlayerStatus.java
@@ -9,32 +9,56 @@
public enum PlayerStatus {
/** Status representing a beginner. */
- NOOB,
+ NOOB(0),
/**
* Status representing a player who has increased
* their net worth by at least 20 percent. */
- NOVICE,
+ NOVICE(20),
/**
* Status representing a player who has increased
* their net worth by at least 50 percent. */
- GOOD,
+ GOOD(50),
/** Status representing a player who has at least doubled their net worth. */
- TRYHARD,
+ TRYHARD(100),
/** Status representing a player who has at least tripled their net worth. */
- PRO,
+ PRO(200),
/**
* Status representing a player who has at least quintupled their
* net worth. */
- SEER,
+ SEER(400),
/**
* Status representing a player who has at least dectupled their
* net worth. */
- OMNIPOTENT;
+ OMNIPOTENT(900);
+
+ /**
+ * Value representing percent increase
+ * from starting money needed to get the respective status.
+ * */
+ private final int percentIncreaseNeeded;
+
+ /**
+ * Constructor.
+ *
+ * @param percentIncreaseNeeded the increase needed to get the status.
+ * */
+ PlayerStatus(final int percentIncreaseNeeded) {
+ this.percentIncreaseNeeded = percentIncreaseNeeded;
+ }
+
+ /**
+ * Getter method for percentincrease needed.
+ *
+ * @return percentIncreaseNeeded.
+ * */
+ public int getPercentIncreaseNeeded() {
+ return percentIncreaseNeeded;
+ }
}
From da76e31b34f077be93a320240fecc97f49754bd3 Mon Sep 17 00:00:00 2001
From: =
Date: Mon, 11 May 2026 13:02:08 +0200
Subject: [PATCH 07/12] Feat: Updated event system to work with channels.
---
pom.xml | 8 ++
.../g40/mappe/service/event/EventChannel.java | 18 +++
.../g40/mappe/service/event/EventData.java | 4 +-
.../g40/mappe/service/event/EventManager.java | 33 +++---
.../g40/mappe/service/event/EventType.java | 20 ++--
.../mappe/service/event/EventManagerTest.java | 98 ++++++++++++++++
.../g40/mappe/view/ViewControllerTest.java | 69 +++++++++++
.../g40/mappe/view/ViewManagerTest.java | 108 ++++++++++++++++++
8 files changed, 330 insertions(+), 28 deletions(-)
create mode 100644 src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/EventChannel.java
create mode 100644 src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/EventManagerTest.java
create mode 100644 src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ViewControllerTest.java
create mode 100644 src/test/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ViewManagerTest.java
diff --git a/pom.xml b/pom.xml
index f65fd07..a9f5520 100644
--- a/pom.xml
+++ b/pom.xml
@@ -27,6 +27,14 @@
6.0.1test
+
+
+
+ org.testfx
+ testfx-junit5
+ 4.0.18
+ test
+
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/EventChannel.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/EventChannel.java
new file mode 100644
index 0000000..e67e360
--- /dev/null
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/EventChannel.java
@@ -0,0 +1,18 @@
+package edu.ntnu.idi.idatt2003.g40.mappe.service.event;
+
+/**
+ * Interface representing an event channel.
+ *
+ *
Used to separate event types into groups.
+ *
+ *
Decreases coupling and enables testing of event types.
+ * */
+public interface EventChannel {
+
+ /**
+ * Getter method for enum name.
+ *
+ * @return String name of enum.
+ * */
+ String getName();
+}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/EventData.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/EventData.java
index 70465f6..b35f098 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/EventData.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/EventData.java
@@ -4,10 +4,10 @@
* Data object sent through the event system by the {@link EventManager}.
*
* @param the type of data this object represents.
- * @param eventType the event type this object represents.
+ * @param channel the event type this object represents.
* @param data the data this object contains.
*
*/
-public record EventData(EventType eventType, T data) {
+public record EventData(EventChannel channel, T data) {
}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/EventManager.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/EventManager.java
index a2bf1b5..a4a2bad 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/EventManager.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/EventManager.java
@@ -1,9 +1,6 @@
package edu.ntnu.idi.idatt2003.g40.mappe.service.event;
-import java.util.ArrayList;
-import java.util.EnumMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
/**
* Event broker in the pub/sub model.
@@ -26,19 +23,19 @@ public final class EventManager {
*
Used to identify which subscribers to fire the event towards.
*
*/
- private final Map> subscriberMap =
- new EnumMap<>(EventType.class);
+ private final Map> subscriberMap =
+ new HashMap<>();
/**
* Method for adding a subscriber to the subscriber map given an event type.
*
- * @param subscriber the {@link EventSubscriber} object to add.
- * @param eventType the {@link EventType} this subscriber should subscribe to.
+ * @param subscriber the {@link EventSubscriber} object to add.
+ * @param eventChannel the {@link EventChannel} type this subscriber should subscribe to.
*
*
*/
- public void addSubscriber(final EventSubscriber subscriber, final EventType eventType) {
- subscriberMap.computeIfAbsent(eventType, k -> new ArrayList<>()).add(subscriber);
+ public void addSubscriber(final EventSubscriber subscriber, final EventChannel eventChannel) {
+ subscriberMap.computeIfAbsent(eventChannel, k -> new ArrayList<>()).add(subscriber);
}
/**
@@ -47,11 +44,19 @@ public void addSubscriber(final EventSubscriber subscriber, final EventType even
* @param the type of event data to send.
* @param data the data to send.
*
- *
+ * @throws IllegalArgumentException if no subscriber is found of the
+ * event type.
*/
- public void invokeEvent(final EventData data) {
- for (EventSubscriber e : subscriberMap.get(data.eventType())) {
- e.handleEvent(data);
+ public void invokeEvent(final EventData data)
+ throws IllegalArgumentException {
+ if (data == null || !subscriberMap.containsKey(data.channel())) {
+ throw new IllegalArgumentException(
+ "No subscriber listening to this event!"
+ );
+ } else {
+ for (EventSubscriber e : subscriberMap.get(data.channel())) {
+ e.handleEvent(data);
+ }
}
}
}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/EventType.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/EventType.java
index 52a60b9..4231866 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/EventType.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/EventType.java
@@ -10,9 +10,8 @@
*
Other
*
*
- *
*/
-public enum EventType {
+public enum EventType implements EventChannel {
/**
* Event type representing events that causes the current scene to change.
@@ -23,16 +22,13 @@ public enum EventType {
* @see edu.ntnu.idi.idatt2003.g40.mappe.view.ViewManager
*
*/
- SCENE_CHANGE,
+ SCENE_CHANGE;
/**
- * Event type representing events that causes the scene to change to the previous one.
- *
- *
Primarily handled by the active
- * {@link edu.ntnu.idi.idatt2003.g40.mappe.view.ViewManager} object.