package com.example; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.chart.LineChart; import javafx.scene.chart.NumberAxis; import javafx.scene.chart.XYChart; import javafx.scene.control.Alert; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.TextField; import javafx.scene.Scene; import java.time.temporal.ChronoUnit; import javafx.util.StringConverter; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.stage.Stage; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.net.URL; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.*; /** * Title:TargetController.java * Description:This is used to handle the management of user saving target * Copyright:Copyright(c) 2024 * @author:Tianyu Zheng * @version:2.3 */ public class TargetController { @FXML private Button infoButton, depButton, tranButton, taskButton, leadButton, savingButton, loutButton, savingSubmitButton; @FXML private LineChart<Number, Number> balanceChart; @FXML private NumberAxis lineChart; @FXML private Label accountBalance, date; @FXML private TextField kidsSavingTarget; private String userId; private Map<String, List<BalanceRecord>> userData; private File balanceFile; @FXML public void initialize() { try { loadUserData(); } catch (Exception e) { e.printStackTrace(); } } /** * Loads user data from a JSON file and initializes the UI. * <p> * This method attempts to load user data from a JSON file located at {@code /balance.json}. * If the file does not exist, it creates a new file with an empty JSON object. * The method then deserializes the user data into a map, identifies the user with an online status, * updates the user interface, and plots the balance chart with the user's balance records. * </p> * * @throws Exception If no online user is found or if an error occurs during file operations. */ private void loadUserData() throws Exception { // Attempt to load the balance file from the resources directory URL resource = getClass().getResource("/balance.json"); if (resource != null) { balanceFile = new File(resource.toURI()); } else { // If the file does not exist, create a new file with an empty JSON object balanceFile = new File("src/main/resources/balance.json"); balanceFile.createNewFile(); try (FileWriter writer = new FileWriter(balanceFile)) { writer.write("{}"); } } // Initialize ObjectMapper to deserialize the user data ObjectMapper mapper = new ObjectMapper(); // Read and deserialize the user data from the balance file userData = mapper.readValue(balanceFile, new TypeReference<Map<String, List<BalanceRecord>>>() {}); // Iterate through the user data to find a user with an online status for (Map.Entry<String, List<BalanceRecord>> entry : userData.entrySet()) { for (BalanceRecord record : entry.getValue()) { if (record.isOnline()) { userId = entry.getKey(); break; } } if (userId != null) break; } // If no online user is found, throw an exception if (userId == null) { throw new Exception("No online user found."); } // Update the UI with the loaded user data updateUI(); // Plot the balance chart with the user's balance records plotBalanceChart(userData.get(userId)); } /** * Updates the user interface elements with the latest user data. * <p> * This method retrieves the latest balance record for the current user, * updates the account balance label, the date label, and the saving target text field. * </p> */ private void updateUI() { // Retrieve the list of balance records for the current user List<BalanceRecord> userRecords = userData.get(userId); // Get the latest balance record BalanceRecord latestRecord = userRecords.get(userRecords.size() - 1); // Update the account balance label with the latest balance accountBalance.setText(String.valueOf(latestRecord.getBalance())); // Update the date label with the current date date.setText(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy.MM.dd"))); // Update the saving target text field with the latest target kidsSavingTarget.setText(String.valueOf(latestRecord.getTarget())); } /** * Plots the balance chart based on the user's balance records. * <p> * This method generates a line chart showing the balance over time * using the provided list of balance records. It calculates the * number of days between each record's target date and a fixed start date, * then plots the balance against the elapsed days. * </p> * * @param userRecords The list of balance records for the user. */ private void plotBalanceChart(List<BalanceRecord> userRecords) { // Create a new series for the chart XYChart.Series<Number, Number> series = new XYChart.Series<>(); series.setName("Balance Over Time"); // Create a list to store the balance data List<XYChart.Data<Number, Number>> balanceData = new ArrayList<>(); // Define the start and end dates for the chart LocalDate startDate = LocalDate.of(2024, 4, 15); LocalDate endDate = LocalDate.of(2024, 6, 10); // Iterate over the user's balance records for (BalanceRecord record : userRecords) { // Parse the target date from the record and calculate the days elapsed LocalDate targetDate = LocalDate.parse(record.getTargetDate(), DateTimeFormatter.ofPattern("yyyy.MM.dd")); long daysElapsed = ChronoUnit.DAYS.between(startDate, targetDate); // Add a new data point to the balance data list balanceData.add(new XYChart.Data<>(daysElapsed, record.getBalance())); } // Sort the balance data by the x-value (days elapsed) balanceData.sort(Comparator.comparing(data -> data.getXValue().longValue())); // Add the sorted balance data to the series series.getData().addAll(balanceData); // Clear existing data from the chart and add the new series balanceChart.getData().clear(); balanceChart.getData().add(series); // Configure the x-axis range and tick labels NumberAxis xAxis = (NumberAxis) balanceChart.getXAxis(); xAxis.setAutoRanging(false); xAxis.setLowerBound(0); xAxis.setUpperBound(ChronoUnit.DAYS.between(startDate, endDate)); xAxis.setTickUnit(5); xAxis.setTickLabelFormatter(new StringConverter<Number>() { @Override public String toString(Number object) { return startDate.plusDays(object.longValue()).format(DateTimeFormatter.ofPattern("yyyy.MM.dd")); } @Override public Number fromString(String string) { return ChronoUnit.DAYS.between(startDate, LocalDate.parse(string, DateTimeFormatter.ofPattern("yyyy.MM.dd"))); } }); } /** * Handles the submission of the saving target by the user. * <p> * This method retrieves the saving target entered by the user, * updates the latest balance record with the new target and current date, * updates the UI to reflect the changes, plots the updated balance chart, * and saves the updated data to a JSON file. * </p> * * @param event The ActionEvent triggered by the submission. */ @FXML public void handleSavingSubmit(ActionEvent event) { try { // Get the saving target entered by the user String targetText = kidsSavingTarget.getText(); // Check if the target text is empty if (targetText.isEmpty()) { showAlert("Error", "Saving target cannot be empty."); return; } // Parse the saving target to an integer int target = Integer.parseInt(targetText); // Find the user with online status true Optional<Map.Entry<String, List<BalanceRecord>>> onlineUserEntry = userData.entrySet().stream() .filter(entry -> entry.getValue().stream().anyMatch(BalanceRecord::isOnline)) .findFirst(); // Check if an online user is found if (onlineUserEntry.isPresent()) { // Retrieve the online user and their balance records Map.Entry<String, List<BalanceRecord>> onlineUser = onlineUserEntry.get(); List<BalanceRecord> userRecords = onlineUser.getValue(); BalanceRecord latestRecord = userRecords.get(userRecords.size() - 1); // Update the latest balance record with the new target and current date latestRecord.setTarget(target); latestRecord.setTargetDate(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy.MM.dd"))); // Update the UI with the latest user data updateUI(); // Update the balance chart plotBalanceChart(userRecords); // Save the updated data to a JSON file saveData(); } else { showAlert("Error", "No online user found."); } } catch (NumberFormatException e) { showAlert("Error", "Invalid number format for saving target."); } catch (Exception e) { showAlert("Error", "An error occurred while processing the saving submit."); e.printStackTrace(); } } /** * Saves the updated user data to the JSON file. * <p> * This method uses the Jackson ObjectMapper to write the updated user data * to the specified JSON file. * </p> */ private void saveData() { try { // Initialize ObjectMapper to serialize the user data ObjectMapper mapper = new ObjectMapper(); // Write the userData map to the balanceFile mapper.writeValue(balanceFile, userData); } catch (IOException e) { // Print the stack trace if an IOException occurs during file writing e.printStackTrace(); } } /** * Displays an alert dialog with the specified title and message. * <p> * This method creates and shows an information alert dialog with the * specified title and message content. * </p> * * @param title The title of the alert dialog. * @param message The message to be displayed in the alert dialog. */ private void showAlert(String title, String message) { // Create a new information alert dialog Alert alert = new Alert(Alert.AlertType.INFORMATION); // Set the title of the alert dialog alert.setTitle(title); // Set the header text to null (no header) alert.setHeaderText(null); // Set the content text (message) of the alert dialog alert.setContentText(message); // Display the alert dialog and wait for user interaction alert.showAndWait(); } @FXML private void switchToInformation(ActionEvent event) { switchScene(event, "/information.fxml"); } @FXML private void switchToDeposit(ActionEvent event) { switchScene(event, "/deposit.fxml"); } @FXML private void switchToTransaction(ActionEvent event) { switchScene(event, "/transaction.fxml"); } @FXML private void switchToTasks(ActionEvent event) { switchScene(event, "/task.fxml"); } @FXML private void switchToLeaderboard(ActionEvent event) { switchScene(event, "/leaderboard.fxml"); } @FXML private void switchToFinancing(ActionEvent event) { switchScene(event, "/financingNor.fxml"); } @FXML private void switchToLogin(ActionEvent event) { switchScene(event, "/login.fxml"); } private void switchScene(ActionEvent event, String fxmlFile) { try { FXMLLoader loader = new FXMLLoader(getClass().getResource(fxmlFile)); Parent root = loader.load(); Stage stage = (Stage) ((Button) event.getSource()).getScene().getWindow(); stage.setScene(new Scene(root)); stage.show(); } catch (IOException e) { e.printStackTrace(); showAlert("Error", "Failed to switch scenes."); } } }
package com.example; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import javafx.application.Platform; import javafx.embed.swing.JFXPanel; import javafx.scene.control.Alert; import javafx.scene.control.ButtonType; import javafx.scene.control.TextField; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.MockedStatic; import org.mockito.Mockito; import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; /** * Title:DepositControllerTest.java * Description:This class is used to test * Copyright:Copyright(c)2024 * @author Tianyu Zheng * @version 2.3 */ public class DepositControllerTest { private DepositController depositController; private ObjectMapper mockMapper; private TextField payerAccount; private TextField recipentAccount; private TextField payee; private TextField transAmount; @BeforeAll public static void initToolkit() { // Initializes JavaFX environment new JFXPanel(); // This will initialize the JavaFX environment } @BeforeEach public void setUp() throws Exception { depositController = new DepositController(); // Mock ObjectMapper mockMapper = Mockito.mock(ObjectMapper.class); Field mapperField = DepositController.class.getDeclaredField("mapper"); mapperField.setAccessible(true); mapperField.set(depositController, mockMapper); // Initialize fields payerAccount = new TextField(); recipentAccount = new TextField(); payee = new TextField(); transAmount = new TextField(); // Set private fields setField("payerAccount", payerAccount); setField("recipentAccount", recipentAccount); setField("payee", payee); setField("transAmount", transAmount); // Initialize JavaFX properties Platform.runLater(() -> { payerAccount.setText("payerBank"); recipentAccount.setText("recipientBank"); payee.setText("payeeName"); transAmount.setText("100"); }); } private void setField(String fieldName, Object value) throws Exception { Field field = DepositController.class.getDeclaredField(fieldName); field.setAccessible(true); field.set(depositController, value); } @Test public void testHandleSubmitApply() throws Exception { Platform.runLater(() -> { try { UserAccount userAccount = new UserAccount("testUser", false, "testPass", 1234567890, "payerBank", null, 1000, null); depositController.setUserAccount(userAccount); List<UserAccount> accounts = new ArrayList<>(); accounts.add(userAccount); accounts.add(new UserAccount("recipientUser", false, "testPass", 1234567891, "recipientBank", null, 500, null)); when(mockMapper.readValue(any(File.class), any(TypeReference.class))).thenReturn(accounts); MockedStatic<Alert> mockedAlert = mockStatic(Alert.class); Alert mockAlert = mock(Alert.class); when(mockAlert.showAndWait()).thenReturn(java.util.Optional.of(ButtonType.OK)); mockedAlert.when(() -> new Alert(Alert.AlertType.INFORMATION)) .then(invocation -> { Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setTitle("Transaction successful"); alert.setContentText("The transaction was completed successfully."); return alert; }); Method handleSubmitApplyMethod = DepositController.class.getDeclaredMethod("handleSubmitApply"); handleSubmitApplyMethod.setAccessible(true); handleSubmitApplyMethod.invoke(depositController); assertEquals(900, userAccount.getBalance()); assertEquals(600, accounts.get(1).getBalance()); verify(mockMapper, times(1)).writeValue(any(File.class), eq(accounts)); mockedAlert.close(); } catch (Exception e) { e.printStackTrace(); fail("Exception thrown: " + e.getMessage()); } }); } }
package com.example; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import javafx.application.Platform; import javafx.embed.swing.JFXPanel; import javafx.event.ActionEvent; import javafx.scene.control.*; import javafx.scene.text.Text; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.MockedStatic; import org.mockito.Mockito; import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; /** * Title:RegistrationControllerTest.java * Description:This class is used to test * Copyright:Copyright(c)2024 * @author Tianyu Zheng * @version 2.3 */ public class RegistrationControllerTest { private RegistrationController registrationController; private ObjectMapper mockMapper; private TextField userIdField; private PasswordField passwordField; private TextField phoneField; private TextField bankLinkedField; private TextField childIdField; private RadioButton parentBool; private RadioButton savingBool; private RadioButton financingBool; private Text childIdText; private Text linkText; /** * Initializes the JavaFX environment before all tests. */ @BeforeAll public static void initToolkit() { new JFXPanel(); // This will initialize the JavaFX environment } /** * Sets up the testing environment before each test. * Initializes the RegistrationController instance, mocks ObjectMapper, and sets the necessary private fields. * * @throws Exception if any reflection errors occur during setup */ @BeforeEach public void setUp() throws Exception { registrationController = new RegistrationController(); // Mock ObjectMapper mockMapper = Mockito.mock(ObjectMapper.class); Field mapperField = RegistrationController.class.getDeclaredField("mapper"); mapperField.setAccessible(true); mapperField.set(registrationController, mockMapper); // Initialize fields userIdField = new TextField(); passwordField = new PasswordField(); phoneField = new TextField(); bankLinkedField = new TextField(); childIdField = new TextField(); parentBool = new RadioButton(); savingBool = new RadioButton(); financingBool = new RadioButton(); childIdText = new Text(); linkText = new Text(); // Set private fields setField("userIdField", userIdField); setField("passwordField", passwordField); setField("phoneField", phoneField); setField("bankLinkedField", bankLinkedField); setField("childIdField", childIdField); setField("parentBool", parentBool); setField("savingBool", savingBool); setField("financingBool", financingBool); setField("childIdText", childIdText); setField("linkText", linkText); // Initialize JavaFX properties Platform.runLater(() -> { userIdField.setText("testUser"); passwordField.setText("testPass"); phoneField.setText("1234567890"); parentBool.setSelected(true); childIdField.setText("child123"); }); } /** * Helper method to set private fields using reflection. * * @param fieldName the name of the field to set * @param value the value to set * @throws Exception if any reflection errors occur */ private void setField(String fieldName, Object value) throws Exception { Field field = RegistrationController.class.getDeclaredField(fieldName); field.setAccessible(true); field.set(registrationController, value); } /** * Tests the registration process for a parent account. * Verifies that the new parent account is added to the accounts list and written to the file. * * @throws Exception if any reflection errors occur during method invocation */ @Test public void testRegisterParent() throws Exception { Platform.runLater(() -> { try { UserAccount newUser = new UserAccount("testUser", true, "testPass", 1234567890, "", "child123", 0, null); List<UserAccount> accounts = new ArrayList<>(); when(mockMapper.readValue(any(File.class), any(TypeReference.class))).thenReturn(accounts); MockedStatic<Alert> mockedAlert = mockStatic(Alert.class); Alert mockAlert = mock(Alert.class); when(mockAlert.showAndWait()).thenReturn(java.util.Optional.of(ButtonType.OK)); mockedAlert.when(() -> new Alert(Alert.AlertType.INFORMATION, "User registered successfully.", ButtonType.OK)) .thenReturn(mockAlert); ActionEvent event = mock(ActionEvent.class); Method registerMethod = RegistrationController.class.getDeclaredMethod("register", ActionEvent.class); registerMethod.setAccessible(true); registerMethod.invoke(registrationController, event); assertTrue(accounts.contains(newUser)); verify(mockMapper, times(1)).writeValue(any(File.class), eq(accounts)); mockedAlert.close(); } catch (Exception e) { e.printStackTrace(); fail("Exception thrown: " + e.getMessage()); } }); } /** * Tests the registration process for a child account. * Verifies that the new child account is added to the accounts list and written to the file. * * @throws Exception if any reflection errors occur during method invocation */ @Test public void testRegisterChild() throws Exception { Platform.runLater(() -> { try { userIdField.setText("testUser"); passwordField.setText("testPass"); phoneField.setText("1234567890"); savingBool.setSelected(true); bankLinkedField.setText("bank123"); UserAccount newUser = new UserAccount("testUser", false, "testPass", 1234567890, "bank123", null, 0, null); List<UserAccount> accounts = new ArrayList<>(); when(mockMapper.readValue(any(File.class), any(TypeReference.class))).thenReturn(accounts); MockedStatic<Alert> mockedAlert = mockStatic(Alert.class); Alert mockAlert = mock(Alert.class); when(mockAlert.showAndWait()).thenReturn(java.util.Optional.of(ButtonType.OK)); mockedAlert.when(() -> new Alert(Alert.AlertType.INFORMATION, "User registered successfully.", ButtonType.OK)) .thenReturn(mockAlert); ActionEvent event = mock(ActionEvent.class); Method registerMethod = RegistrationController.class.getDeclaredMethod("register", ActionEvent.class); registerMethod.setAccessible(true); registerMethod.invoke(registrationController, event); assertTrue(accounts.contains(newUser)); verify(mockMapper, times(1)).writeValue(any(File.class), eq(accounts)); mockedAlert.close(); } catch (Exception e) { e.printStackTrace(); fail("Exception thrown: " + e.getMessage()); } }); } /** * Tests the handleParentCheckBox method. * Verifies the visibility and manageability of fields when the parent checkbox is selected. * * @throws Exception if any reflection errors occur during method invocation */ @Test public void testHandleParentCheckBox() throws Exception { Platform.runLater(() -> { try { parentBool.setSelected(true); Method handleParentCheckBoxMethod = RegistrationController.class.getDeclaredMethod("handleParentCheckBox"); handleParentCheckBoxMethod.setAccessible(true); handleParentCheckBoxMethod.invoke(registrationController); assertTrue(childIdField.isVisible()); assertTrue(childIdField.isManaged()); assertTrue(childIdText.isVisible()); assertTrue(childIdText.isManaged()); assertFalse(linkText.isVisible()); assertFalse(linkText.isManaged()); assertFalse(bankLinkedField.isVisible()); assertFalse(bankLinkedField.isManaged()); savingBool.setSelected(true); handleParentCheckBoxMethod.invoke(registrationController); assertFalse(childIdField.isVisible()); assertFalse(childIdField.isManaged()); assertFalse(childIdText.isVisible()); assertFalse(childIdText.isManaged()); assertTrue(linkText.isVisible()); assertTrue(linkText.isManaged()); assertTrue(bankLinkedField.isVisible()); assertTrue(bankLinkedField.isManaged()); } catch (Exception e) { e.printStackTrace(); fail("Exception thrown: " + e.getMessage()); } }); } }
package com.example; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; import javafx.application.Platform; import javafx.embed.swing.JFXPanel; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; /** * Title:TaskControllerTest.java * Description:This class is used to test * Copyright:Copyright(c)2024 * @author Tianyu Zheng * @version 2.3 */ public class TaskControllerTest { private TaskController taskController; private UserAccount mockUserAccount; /** * Sets up the testing environment before each test. * Initializes the JavaFX environment, creates the TaskController instance, * mocks the UserAccount, and sets the necessary private fields. * * @throws Exception if any reflection errors occur during setup */ @BeforeEach public void setUp() throws Exception { // Initialize JavaFX environment new JFXPanel(); taskController = new TaskController(); // Mock user account mockUserAccount = Mockito.mock(UserAccount.class); when(mockUserAccount.getUserId()).thenReturn("testUser"); // Set private field userAccount Field userAccountField = TaskController.class.getDeclaredField("userAccount"); userAccountField.setAccessible(true); userAccountField.set(taskController, mockUserAccount); // Initialize the table and columns TableView<Task> table = new TableView<>(); TableColumn<Task, String> taskField = new TableColumn<>("Task"); TableColumn<Task, String> contentField = new TableColumn<>("Content"); TableColumn<Task, String> status = new TableColumn<>("Status"); TableColumn<Task, Double> bounty = new TableColumn<>("Bounty"); TableColumn<Task, String> acceptOrNot = new TableColumn<>("Accept Or Not"); table.getColumns().addAll(taskField, contentField, status, bounty, acceptOrNot); // Set private fields table and columns setPrivateField(taskController, "table", table); setPrivateField(taskController, "taskField", taskField); setPrivateField(taskController, "contentField", contentField); setPrivateField(taskController, "status", status); setPrivateField(taskController, "bounty", bounty); setPrivateField(taskController, "acceptOrNot", acceptOrNot); // Initialize tasks List<Task> tasks = new ArrayList<>(); tasks.add(new Task("1", "parent1", "testUser", "Task1", "Content1", 10.0, "yes", "to be received")); tasks.add(new Task("2", "parent2", "testUser", "Task2", "Content2", 20.0, "no", "accepted")); setPrivateField(taskController, "allTasks", tasks); // Set up JavaFX environment for tests Platform.runLater(() -> { try { taskController.initialize1(); } catch (Exception e) { e.printStackTrace(); } }); } /** * Tests the handleAccept method. * Verifies that the status of the task is updated to "accepted". * * @throws Exception if any reflection errors occur during method invocation */ @Test public void testHandleAccept() throws Exception { Platform.runLater(() -> { try { Method handleAcceptMethod = TaskController.class.getDeclaredMethod("handleAccept", Task.class); handleAcceptMethod.setAccessible(true); Task task = new Task("3", "parent3", "testUser", "Task3", "Content3", 30.0, "yes", "to be received"); handleAcceptMethod.invoke(taskController, task); assertEquals("accepted", task.getStatus()); } catch (Exception e) { e.printStackTrace(); fail("Exception thrown: " + e.getMessage()); } }); } /** * Tests the handleReject method. * Verifies that the status of the task is updated to "reject". * * @throws Exception if any reflection errors occur during method invocation */ @Test public void testHandleReject() throws Exception { Platform.runLater(() -> { try { Method handleRejectMethod = TaskController.class.getDeclaredMethod("handleReject", Task.class); handleRejectMethod.setAccessible(true); Task task = new Task("4", "parent4", "testUser", "Task4", "Content4", 40.0, "no", "to be received"); handleRejectMethod.invoke(taskController, task); assertEquals("reject", task.getStatus()); } catch (Exception e) { e.printStackTrace(); fail("Exception thrown: " + e.getMessage()); } }); } /** * Tests the handleSubmit method. * Verifies that the status of the task is updated to "to be reviewed". * * @throws Exception if any reflection errors occur during method invocation */ @Test public void testHandleSubmit() throws Exception { Platform.runLater(() -> { try { Method handleSubmitMethod = TaskController.class.getDeclaredMethod("handleSubmit", Task.class); handleSubmitMethod.setAccessible(true); Task task = new Task("5", "parent5", "testUser", "Task5", "Content5", 50.0, "yes", "accepted"); handleSubmitMethod.invoke(taskController, task); assertEquals("to be reviewed", task.getStatus()); } catch (Exception e) { e.printStackTrace(); fail("Exception thrown: " + e.getMessage()); } }); } /** * Helper method to set private fields using reflection. * * @param target the target object * @param fieldName the name of the field to set * @param value the value to set * @throws Exception if any reflection errors occur */ private void setPrivateField(Object target, String fieldName, Object value) throws Exception { Field field = target.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(target, value); } }