Skip to content

CodeRabbit Review#7

Open
kngys wants to merge 60 commits into
coderabbitfrom
master
Open

CodeRabbit Review#7
kngys wants to merge 60 commits into
coderabbitfrom
master

Conversation

@kngys

@kngys kngys commented Sep 1, 2025

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features
    • Introduced a JavaFX chat-style GUI with auto-scrolling dialog bubbles.
    • Task management: add todo/deadline/event, list, find, update, delete, mark/unmark.
    • Persistent storage of tasks and improved greetings/exit flow.
  • Documentation
    • Revamped User Guide with full command reference and UI screenshot.
  • Tests
    • Added unit and text UI tests covering storage parsing and task list behaviors.
  • Chores
    • Rebranded to “Serenity” and renamed output to serenity.jar.
    • Enabled assertions and enforced code style checks.

kngys and others added 26 commits September 5, 2024 00:01
There are currently no assertion statements in the code.

Assertion statements define our assumptions of the program state. These
assumptions are verified at runtime, allowing errors to be caught early.

Let's add some assertion statements to ensure our assumptions about the
program state are true.
The current code has areas for improvement in terms of code quality.

Improving code quality allows for code to be better read, understood
and modified by other developers.

Let's
*Shorten methods
*Improve logical structure of code
*Remove unnecessary comments
*Refactor by extracting methods
# Conflicts:
#	src/main/java/serenity/Parser.java
@coderabbitai

coderabbitai Bot commented Sep 1, 2025

Copy link
Copy Markdown

Walkthrough

Replaces Duke with Serenity, introducing core bot logic, task domain, storage, parser, CLI and JavaFX GUI, and tests. Adds Checkstyle configuration and Gradle updates (JavaFX deps, main class switch, shadowJar rename). Removes old Duke entry point. Updates docs, sample data, and text UI tests.

Changes

Cohort / File(s) Summary
Build & Packaging
build.gradle
Added Checkstyle plugin/config; centralized JavaFX 17.0.7 platform deps; switched main class to serenity.gui.Launcher; renamed shadowJar to serenity.jar; enabled assertions in run task.
Static Analysis Config
config/checkstyle/checkstyle.xml, config/checkstyle/suppressions.xml
Added comprehensive Checkstyle rules and suppressions for test Javadoc checks.
Documentation
docs/README.md
Rewrote user guide for Serenity with full command set and UI reference.
Data Seed
data/serenity.txt
Appended four sample task records.
CLI Replacement
src/main/java/Duke.java
Removed legacy Duke main class.
Core App Wiring
src/main/java/serenity/Serenity.java, src/main/java/serenity/SerenityException.java
Added app orchestrator, greeting/response methods, CLI loop, and custom exception.
Parsing & Control
src/main/java/serenity/Parser.java
Added command router handling CRUD, status changes, search, update, exit; UI and string-return variants.
Persistence
src/main/java/serenity/Storage.java
Added file IO for tasks, line parsing/serialization, full overwrite and append operations.
CLI UI
src/main/java/serenity/Ui.java
Added console IO utilities for messages, task lists, and lifecycle prompts.
Domain: Tasks
src/main/java/serenity/task/Task.java, .../Todo.java, .../Deadline.java, .../Event.java, .../TaskList.java
Added task hierarchy (Todo/Deadline/Event), formatting, state changes, parsing helpers, list management (add/delete/mark/unmark/find/update).
GUI: JavaFX Entrypoints
src/main/java/serenity/gui/Launcher.java, .../Main.java
Added JavaFX launcher and Application starter loading FXML and injecting Serenity.
GUI: Controls
src/main/java/serenity/gui/MainWindow.java, .../DialogBox.java
Added main window controller and dialog component with flip layout for user/bot messages.
GUI: FXML Resources
src/main/resources/view/MainWindow.fxml, .../DialogBox.fxml
Added layouts for main window and dialog boxes.
Unit Tests
src/test/java/serenity/StorageTest.java, .../TaskListTest.java, .../TodoTest.java
Added tests for storage parsing, task list behaviors, and Todo formatting.
Text UI Tests
text-ui-test/input.txt, .../EXPECTED.TXT, .../runtest.bat
Added input script, updated expected output for Serenity, and corrected batch runner to invoke Serenity.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant CLI as Ui (CLI)
  participant Core as Serenity
  participant Parser as Parser
  participant Tasks as TaskList
  participant Store as Storage

  User->>CLI: Enter command
  CLI->>Core: readCommand()
  Core->>Parser: parse(input, tasks, ui, storage)
  alt create (todo/deadline/event)
    Parser->>Tasks: createTask(input)
    Parser->>Tasks: addTask(task)
    Parser->>Store: saveTask(task) or writeToFile(tasks)
    Parser-->>CLI: showMessage(...)
  else list/find
    Parser->>Tasks: toString()/findTask()
    Parser-->>CLI: showTaskList/showMessage
  else mark/unmark/delete/update
    Parser->>Tasks: mutate(...)
    Parser->>Store: writeToFile(tasks)
    Parser-->>CLI: showMessage(...)
  else bye
    Parser-->>CLI: showGoodbye()
  end
Loading
sequenceDiagram
  autonumber
  actor User
  participant FX as JavaFX Stage
  participant MW as MainWindow
  participant Core as Serenity
  participant Parser as Parser
  participant Tasks as TaskList
  participant Store as Storage

  Note over FX,MW: App start
  FX->>MW: initialize() + start()
  MW->>Core: welcome()
  MW->>MW: render welcome dialog

  User->>MW: type message + Send
  MW->>Core: getResponse(input)
  Core->>Parser: parseToString(input, tasks, storage)
  Parser->>Tasks: operations (create/list/mark/...)
  Parser->>Store: save/write as needed
  Parser-->>Core: response string
  Core-->>MW: response string
  MW->>MW: append user + bot DialogBox
  alt input == "bye"
    MW->>FX: close stage
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

In burrows of code I hop with glee,
Duke waves goodbye—hello, Serenity!
Checkstyle carrots, JavaFX skies,
Tasks in a basket neatly rise.
Parser paths and storage trails,
Tests thump approval with fluffy tails.
Hippity-hop—our release prevails! 🥕✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch master

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@kngys

kngys commented Sep 1, 2025

Copy link
Copy Markdown
Owner Author

@CodeRabbit review

@coderabbitai

coderabbitai Bot commented Sep 1, 2025

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 30

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
text-ui-test/runtest.bat (1)

10-14: Compile step misses subpackages; tests won’t build

The current javac glob only compiles top-level sources and will skip package directories like serenity/gui.

-rem compile the code into the bin folder
-javac  -cp ..\src\main\java -Xlint:none -d ..\bin ..\src\main\java\*.java
+REM compile all sources (including subpackages) into the bin folder
+dir /s /b ..\src\main\java\*.java > sources.txt
+javac -cp ..\src\main\java -Xlint:none -d ..\bin @sources.txt
+if exist sources.txt del sources.txt
🧹 Nitpick comments (39)
config/checkstyle/suppressions.xml (1)

8-9: Optionally narrow the files regex to test sources only.

Prevents accidental suppression if a non-test file ends with “Test.java” elsewhere.

Example:

-    <suppress checks="JavadocType" files=".*Test\.java"/>
-    <suppress checks="MissingJavadocMethod" files=".*Test\.java"/>
+    <suppress checks="JavadocType" files="^src/test/java/.*Test\.java$"/>
+    <suppress checks="MissingJavadocMethod" files="^src/test/java/.*Test\.java$"/>
text-ui-test/input.txt (1)

1-9: Happy-path coverage looks good; consider adding a few negative/edge cases.

Add 1–2 invalid commands (e.g., “mark 99”, malformed deadlines) to guard parser error paths. Keep in a separate test input to avoid bloating this one.

text-ui-test/EXPECTED.TXT (1)

1-4: Freeze UI header/footer strings as constants to avoid brittle test diffs.

If not already, centralize these separators and messages in Ui; keeps tests stable when branding changes.

Also applies to: 5-6, 10-13, 15-18, 20-25, 26-29, 30-33, 34-37, 38-43, 44-46

data/serenity.txt (1)

1-4: Add one future-dated and one malformed entry to a dedicated negative test fixture.

Helps verify Storage error handling without risking main sample integrity.

src/main/java/serenity/SerenityException.java (2)

3-6: Clarify Javadoc: it’s an app-level exception, not “in the Serenity class.”

Minor wording improvement.

Apply this diff:

-/**
- * Represents a custom exception in the Serenity class.
- */
+/**
+ * Application-level exception type for Serenity.
+ */

6-16: Add serialVersionUID and overloads for flexibility.

Improves serialization safety and lets callers pass causes.

Apply this diff:

 public class SerenityException extends Exception {
+    private static final long serialVersionUID = 1L;
 
     /**
      * Constructs a SerenityException.
      *
      * @param msg The error message of the exception.
      */
     public SerenityException(String msg) {
         super(msg);
     }
+
+    /**
+     * Constructs a SerenityException with a cause.
+     *
+     * @param msg   the error message
+     * @param cause the underlying cause
+     */
+    public SerenityException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
 }
src/main/resources/view/DialogBox.fxml (2)

8-18: Ensure bubbles wrap properly and don’t crowd the avatar

Add spacing and let the Label grow horizontally so long messages wrap instead of overlapping the ImageView.

-<fx:root alignment="TOP_RIGHT"
+<fx:root alignment="TOP_RIGHT" spacing="10.0"
@@
-        <Label fx:id="dialog" text="Label" wrapText="true" minHeight="-Infinity"/>
+        <Label fx:id="dialog" text="Label" wrapText="true" minHeight="-Infinity" HBox.hgrow="ALWAYS" maxWidth="1.7976931348623157E308"/>

11-11: Avoid hard-coding prefWidth to improve responsiveness

Let the parent/container decide width. The fixed 400px can cause awkward wrapping on wider windows.

-         prefWidth="400.0"
src/main/java/serenity/task/Task.java (1)

15-18: Null-safety for description

Guard against null descriptions to avoid surprises elsewhere (e.g., rendering).

+import java.util.Objects;
@@
-    public Task(String description) {
-        this.description = description;
+    public Task(String description) {
+        this.description = Objects.requireNonNull(description, "description");
         this.isDone = false;
     }
docs/README.md (3)

73-79: Grammar: plural agreement

“Tasks … which contain”, not “contains”.

-Finds all tasks in the task list which contains the given keyword.
+Finds all tasks in the task list which contain the given keyword.

60-61: Clarify unmark semantics

Say “mark as not done” to avoid confusion.

-Unmarks the task at the given index as done.
+Marks the task at the given index as not done.

102-104: Tighten phrasing per LanguageTool hint

Improve readability.

-- The task type is either `todo`, `deadline`, or `event`
-- The description required is dependent on the task type  
+- The task type is one of: `todo`, `deadline`, `event`
+- The required description depends on the task type.
src/test/java/serenity/TodoTest.java (1)

10-18: Broaden coverage: test marked state and edge descriptions.

Add tests for marked tasks (expect “[T][X] …” and “T | 1 | …”) and tricky descriptions (leading/trailing spaces, Unicode).

Example additional test:

@Test
public void testMarkedAndData() {
    Todo t = new Todo("read book");
    t.mark();
    assertEquals("[T][X] read book", t.toString());
    assertEquals("T | 1 | read book", t.formatData());
}
src/main/java/serenity/gui/Main.java (3)

12-14: Update Javadoc branding to Serenity.

-/**
- * A GUI for Duke using FXML.
- */
+/**
+ * Serenity GUI using FXML.
+ */

21-35: Fail fast on missing FXML and show a user-friendly error dialog.

Null FXML URL or load failures currently just print a stack trace. Guard the resource and surface an Alert, then exit cleanly.

-        try {
-            FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("/view/MainWindow.fxml"));
+        try {
+            var fxml = Main.class.getResource("/view/MainWindow.fxml");
+            if (fxml == null) {
+                throw new IOException("Missing resource: /view/MainWindow.fxml");
+            }
+            FXMLLoader fxmlLoader = new FXMLLoader(fxml);
             AnchorPane ap = fxmlLoader.load();
             Scene scene = new Scene(ap);
             stage.setScene(scene);
             stage.setTitle("Serenity");
             // inject the serenity instance
-            MainWindow window = fxmlLoader.<MainWindow>getController();
+            MainWindow window = fxmlLoader.getController();
             window.setSerenity(serenity);
             window.start();
             stage.show();
         } catch (IOException e) {
-            e.printStackTrace();
+            var alert = new javafx.scene.control.Alert(javafx.scene.control.Alert.AlertType.ERROR);
+            alert.setHeaderText("Failed to load UI");
+            alert.setContentText(e.getMessage());
+            alert.showAndWait();
+            javafx.application.Platform.exit();
         }

Add imports:

import javafx.application.Platform;
import javafx.scene.control.Alert;

28-28: Drop redundant explicit generic on getController().

-            MainWindow window = fxmlLoader.<MainWindow>getController();
+            MainWindow window = fxmlLoader.getController();
src/main/resources/view/MainWindow.fxml (1)

16-42: Prefer anchors over absolute layout for responsive resizing; bind content width.

Replace layoutX/layoutY with AnchorPane anchors and enable fitToWidth so the dialog stretches with the window.

         <TextField fx:id="userInput"
-                   layoutY="558.0"
                    onAction="#handleUserInput"
                    prefHeight="41.0"
                    prefWidth="324.0"
-                   AnchorPane.bottomAnchor="1.0" />
+                   AnchorPane.leftAnchor="0.0"
+                   AnchorPane.rightAnchor="76.0"
+                   AnchorPane.bottomAnchor="1.0" />
         <Button fx:id="sendButton"
-                layoutX="324.0"
-                layoutY="558.0"
                 mnemonicParsing="false"
                 onAction="#handleUserInput"
                 prefHeight="41.0"
                 prefWidth="76.0"
-                text="Send" />
+                text="Send"
+                AnchorPane.rightAnchor="0.0"
+                AnchorPane.bottomAnchor="1.0" />
         <ScrollPane fx:id="scrollPane"
                     hbarPolicy="NEVER"
                     hvalue="1.0"
-                    prefHeight="557.0"
-                    prefWidth="400.0"
-                    vvalue="1.0">
+                    vvalue="1.0"
+                    fitToWidth="true"
+                    AnchorPane.topAnchor="0.0"
+                    AnchorPane.leftAnchor="0.0"
+                    AnchorPane.rightAnchor="0.0"
+                    AnchorPane.bottomAnchor="42.0">
             <content>
                 <VBox fx:id="dialogContainer"
-                      prefHeight="552.0"
-                      prefWidth="388.0" />
+                      prefHeight="552.0"
+                      prefWidth="388.0"
+                      fillWidth="true"/>
             </content>
         </ScrollPane>
src/main/java/serenity/task/Event.java (1)

19-23: Validate inputs to protect persistence format.

Guard against nulls and disallow the ‘|’ delimiter in fields to avoid corrupting saved data.

     public Event(String description, String start, String end) {
         super(description);
-        this.start = start;
-        this.end = end;
+        if (start == null || end == null) {
+            throw new IllegalArgumentException("start/end must not be null");
+        }
+        if (start.contains("|") || end.contains("|")) {
+            throw new IllegalArgumentException("start/end must not contain '|'");
+        }
+        this.start = start;
+        this.end = end;
     }

If preferred, we can instead escape ‘|’ on write and unescape on read; say the word and I’ll draft both sides.

src/main/java/serenity/gui/MainWindow.java (5)

28-30: Harden image resource loading to avoid NPEs.

getResourceAsStream may return null at runtime; construct Images via a small helper with a null check.

-    private Image userImage = new Image(this.getClass().getResourceAsStream("/images/User.png"));
-    private Image serenityImage = new Image(this.getClass().getResourceAsStream("/images/Serenity.png"));
+    private final Image userImage = loadImage("/images/User.png");
+    private final Image serenityImage = loadImage("/images/Serenity.png");
+
+    private Image loadImage(String path) {
+        var is = java.util.Objects.requireNonNull(
+                this.getClass().getResourceAsStream(path),
+                "Missing resource: " + path);
+        return new Image(is);
+    }

36-39: Guard injection for robustness.

Fail fast if serenity is not provided.

-    public void setSerenity(Serenity s) {
-        serenity = s;
-    }
+    public void setSerenity(Serenity s) {
+        this.serenity = java.util.Objects.requireNonNull(s, "Serenity must be injected before use");
+    }

45-47: Avoid possible NPE on startup.

If start() is called before setSerenity(...), this will NPE.

-    public void start() {
-        dialogContainer.getChildren().addAll(DialogBox.getSerenityDialog(serenity.welcome(), serenityImage));
-    }
+    public void start() {
+        if (serenity == null) {
+            throw new IllegalStateException("Serenity not injected. Call setSerenity(...) before start().");
+        }
+        dialogContainer.getChildren().add(DialogBox.getSerenityDialog(serenity.welcome(), serenityImage));
+    }

49-52: Rename “Duke” to “Serenity” in Javadoc.

-     * Creates two dialog boxes, one echoing user input and the other containing Duke's reply and then appends them to
+     * Creates two dialog boxes, one echoing user input and the other containing Serenity's reply, and appends them to

54-65: Trim/ignore empty input and handle case-insensitive exit.

Prevents blank message bubbles and supports “BYE/Bye”.

-    private void handleUserInput() {
-        String input = userInput.getText();
+    private void handleUserInput() {
+        String input = userInput.getText().trim();
+        if (input.isEmpty()) {
+            return;
+        }
         String response = serenity.getResponse(input);
         dialogContainer.getChildren().addAll(
                 DialogBox.getUserDialog(input, userImage),
                 DialogBox.getSerenityDialog(response, serenityImage)
         );
         userInput.clear();
-        if (input.equals("bye")) {
+        if (input.equalsIgnoreCase("bye")) {
             Platform.exit();
         }
     }
src/main/java/serenity/task/Deadline.java (3)

16-17: Define shared DateTimeFormatters once.

Avoid recreating formatters and keep formats consistent.

     protected LocalDate date;
+    private static final DateTimeFormatter INPUT_FMT = DateTimeFormatter.ofPattern("dd/MM/yyyy");
+    private static final DateTimeFormatter OUTPUT_FMT = DateTimeFormatter.ofPattern("dd MMM yyyy");

41-43: Reuse formatter constant.

-        String formatDate = date.format(DateTimeFormatter.ofPattern("dd MMM yyyy"));
+        String formatDate = date.format(OUTPUT_FMT);

51-54: Reuse formatter constant (save format).

-        String formatDate = date.format(DateTimeFormatter.ofPattern("dd MMM yyyy"));
+        String formatDate = date.format(OUTPUT_FMT);

Confirm Storage.load/save expects this display format; otherwise consider persisting ISO-8601 (yyyy-MM-dd) and formatting only for UI.

src/main/java/serenity/gui/DialogBox.java (1)

29-35: Decouple FXML lookup and fail fast on load errors.

Use DialogBox.class for resource resolution and throw a runtime exception instead of printing the stack trace.

-            FXMLLoader fxmlLoader = new FXMLLoader(MainWindow.class.getResource("/view/DialogBox.fxml"));
+            FXMLLoader fxmlLoader = new FXMLLoader(DialogBox.class.getResource("/view/DialogBox.fxml"));
             fxmlLoader.setController(this);
             fxmlLoader.setRoot(this);
             fxmlLoader.load();
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
+        } catch (IOException e) {
+            throw new IllegalStateException("Failed to load /view/DialogBox.fxml", e);
+        }
src/test/java/serenity/TaskListTest.java (1)

101-110: Consistent test naming.

Use lower camel case: updateTask_deadline_success.

src/main/java/serenity/Serenity.java (1)

89-91: Use the default path consistently

Main should rely on the default constructor to avoid duplicating the file path string.

Apply this diff:

-        new Serenity("./data/serenity.txt").run();
+        new Serenity().run();
src/main/java/serenity/task/TaskList.java (3)

109-110: Fix Javadoc: wrong return type description

Docstring says “Deadline” for createTodo; should be “Todo”.

Apply this diff:

-     * @return Deadline with given task description.
+     * @return Todo with given task description.

265-272: Use StringBuilder to avoid quadratic concatenation in toString

For long lists, repeated string concatenation is inefficient.

Apply this diff:

     @Override
     public String toString() {
-        String message = "Here are the tasks in your list:";
-        for (int i = 0; i < tasks.size(); i++) {
-            int index = i + 1;
-            message += "\n" + index + ". " + tasks.get(i);
-        }
-        return message;
+        StringBuilder sb = new StringBuilder("Here are the tasks in your list:");
+        for (int i = 0; i < tasks.size(); i++) {
+            sb.append('\n').append(i + 1).append(". ").append(tasks.get(i));
+        }
+        return sb.toString();
     }

279-285: Use StringBuilder in formatData

Same concatenation concern as toString.

Apply this diff:

     public String formatData() {
-        String data = "";
-        for (int i = 0; i < tasks.size(); i++) {
-            data += tasks.get(i).formatData() + "\n";
-        }
-        return data;
+        StringBuilder data = new StringBuilder();
+        for (int i = 0; i < tasks.size(); i++) {
+            data.append(tasks.get(i).formatData()).append('\n');
+        }
+        return data.toString();
     }
src/test/java/serenity/StorageTest.java (2)

3-3: Add import for assertThrows.

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

21-28: Avoid relying on toString() for semantic equality.

Comparing toString() is brittle. Prefer asserting type and core fields (description, date, done) directly, or implement equals/hashCode for tasks and compare objects.

src/main/java/serenity/Storage.java (2)

25-34: Tighten encapsulation of filePath.

Make filePath private final; it never changes after construction.

-    protected String filePath;
+    private final String filePath;

51-52: Assertion is a no-op in production.

Either remove it or convert to a runtime check with a meaningful exception.

config/checkstyle/checkstyle.xml (1)

238-239: Remove duplicate AtclauseOrder module.

Defined twice; keep one to avoid duplicate checks.

-        <module name="AtclauseOrder"/>

(Apply to either the earlier or later occurrence, keeping a single definition.)

Also applies to: 388-390

src/main/java/serenity/Parser.java (2)

130-132: Make exit check robust to surrounding whitespace.

-        return input.startsWith("bye");
+        return input != null && input.trim().equals("bye");

33-67: Minor: reduce duplication between parse and parseToString.

Consider extracting a common command dispatcher that returns a result object (message + side effects flag), used by both methods.

Also applies to: 86-117

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 81a9c53 and ac6329a.

⛔ Files ignored due to path filters (3)
  • docs/Ui.png is excluded by !**/*.png
  • src/main/resources/images/Serenity.png is excluded by !**/*.png
  • src/main/resources/images/User.png is excluded by !**/*.png
📒 Files selected for processing (28)
  • build.gradle (3 hunks)
  • config/checkstyle/checkstyle.xml (1 hunks)
  • config/checkstyle/suppressions.xml (1 hunks)
  • data/serenity.txt (1 hunks)
  • docs/README.md (1 hunks)
  • src/main/java/Duke.java (0 hunks)
  • src/main/java/serenity/Parser.java (1 hunks)
  • src/main/java/serenity/Serenity.java (1 hunks)
  • src/main/java/serenity/SerenityException.java (1 hunks)
  • src/main/java/serenity/Storage.java (1 hunks)
  • src/main/java/serenity/Ui.java (1 hunks)
  • src/main/java/serenity/gui/DialogBox.java (1 hunks)
  • src/main/java/serenity/gui/Launcher.java (1 hunks)
  • src/main/java/serenity/gui/Main.java (1 hunks)
  • src/main/java/serenity/gui/MainWindow.java (1 hunks)
  • src/main/java/serenity/task/Deadline.java (1 hunks)
  • src/main/java/serenity/task/Event.java (1 hunks)
  • src/main/java/serenity/task/Task.java (1 hunks)
  • src/main/java/serenity/task/TaskList.java (1 hunks)
  • src/main/java/serenity/task/Todo.java (1 hunks)
  • src/main/resources/view/DialogBox.fxml (1 hunks)
  • src/main/resources/view/MainWindow.fxml (1 hunks)
  • src/test/java/serenity/StorageTest.java (1 hunks)
  • src/test/java/serenity/TaskListTest.java (1 hunks)
  • src/test/java/serenity/TodoTest.java (1 hunks)
  • text-ui-test/EXPECTED.TXT (1 hunks)
  • text-ui-test/input.txt (1 hunks)
  • text-ui-test/runtest.bat (1 hunks)
💤 Files with no reviewable changes (1)
  • src/main/java/Duke.java
🧰 Additional context used
🪛 LanguageTool
docs/README.md

[grammar] ~102-~102: There might be a mistake here.
Context: ...k type is either todo, deadline, or event - The description required is dependent on...

(QB_NEW_EN)

text-ui-test/EXPECTED.TXT

[grammar] ~2-~2: There might be a mistake here.
Context: ...______________________ Hi, I'm Serenity! What can I do for you? _________________...

(QB_NEW_EN)


[grammar] ~6-~6: There might be a mistake here.
Context: ...__________ Got it. I've added this task: [T][ ] read book Now you have 1 task in ...

(QB_NEW_EN)


[grammar] ~11-~11: There might be a mistake here.
Context: ...__________ Got it. I've added this task: [D][ ] return book (by: Sunday) Now you ...

(QB_NEW_EN)


[grammar] ~16-~16: There might be a mistake here.
Context: ...__________ Got it. I've added this task: [E][ ] project meeting (from: Mon 2pm to...

(QB_NEW_EN)


[grammar] ~17-~17: There might be a mistake here.
Context: ... project meeting (from: Mon 2pm to: 4pm) Now you have 3 tasks in the list. ______...

(QB_NEW_EN)


[grammar] ~21-~21: There might be a mistake here.
Context: ..._______ Here are the tasks in your list: 1. [T][ ] read book 2. [D][ ] return book (...

(QB_NEW_EN)


[grammar] ~22-~22: There might be a mistake here.
Context: ... tasks in your list: 1. [T][ ] read book 2. [D][ ] return book (by: Sunday) 3. [E][ ...

(QB_NEW_EN)


[grammar] ~23-~23: There might be a mistake here.
Context: ... book 2. [D][ ] return book (by: Sunday) 3. [E][ ] project meeting (from: Mon 2pm to...

(QB_NEW_EN)


[grammar] ~27-~27: There might be a mistake here.
Context: ...___ Nice! I've marked this task as done: [T][X] read book _______________________...

(QB_NEW_EN)


[grammar] ~31-~31: There might be a mistake here.
Context: ...___ Nice! I've marked this task as done: [E][X] project meeting (from: Mon 2pm to...

(QB_NEW_EN)


[grammar] ~35-~35: There might be a mistake here.
Context: ..., I've marked this task as not done yet: [T][ ] read book _______________________...

(QB_NEW_EN)


[grammar] ~39-~39: There might be a mistake here.
Context: ..._______ Here are the tasks in your list: 1. [T][ ] read book 2. [D][ ] return book (...

(QB_NEW_EN)


[grammar] ~40-~40: There might be a mistake here.
Context: ... tasks in your list: 1. [T][ ] read book 2. [D][ ] return book (by: Sunday) 3. [E][X...

(QB_NEW_EN)


[grammar] ~41-~41: There might be a mistake here.
Context: ... book 2. [D][ ] return book (by: Sunday) 3. [E][X] project meeting (from: Mon 2pm to...

(QB_NEW_EN)


[style] ~45-~45: Using many exclamation marks might seem excessive (in this case: 4 exclamation marks for a text that’s 841 characters long)
Context: ...____ Goodbye. Hope to see you again soon! _______________________________________...

(EN_EXCESSIVE_EXCLAMATION)

🔇 Additional comments (8)
text-ui-test/EXPECTED.TXT (1)

1-46: EXPECTED matches the provided input; no functional issues spotted.

Output lines and task counts align with the commands sequence.

data/serenity.txt (1)

1-4: LGTM: sample data formats look consistent with typical iP storage.

Date/times and done flags look coherent.

src/main/java/serenity/gui/Launcher.java (1)

9-11: LGTM: minimal, correct JavaFX launcher

Works around JavaFX classpath issues cleanly.

src/test/java/serenity/TodoTest.java (1)

10-18: Solid, focused assertions for Todo’s string and persistence formats.

Both expectations match the current Todo implementation and provide good guardrails.

src/main/java/serenity/task/Todo.java (1)

22-25: Todo string and data formats are correct and consistent with tests.

Also applies to: 32-35

src/test/java/serenity/StorageTest.java (2)

12-18: LGTM: happy path (Todo) is covered clearly.


30-37: LGTM: event deserialization test reads well and is precise.

config/checkstyle/checkstyle.xml (1)

1-434: Verify Checkstyle config loads with Gradle 10.2 toolVersion
Ensure JAVA_HOME points to a valid JDK (e.g. Java 17), then run:

export JAVA_HOME=/path/to/valid/jdk
./gradlew --no-daemon checkstyleMain checkstyleTest -i

Confirm the config parses without errors.

Comment thread build.gradle
Comment on lines +15 to +28
String javaFxVersion = '17.0.7'

implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'win'
implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'mac'
implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'linux'
implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'win'
implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'mac'
implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'linux'
implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'win'
implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'mac'
implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'linux'
implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'win'
implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'mac'
implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'linux'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid bundling all OS JavaFX artifacts; use the OpenJFX Gradle plugin.

Shading win/mac/linux variants together bloats the JAR and can cause native clashes. Let the plugin resolve platform-specific artifacts at build/run time.

-    String javaFxVersion = '17.0.7'
-
-    implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'win'
-    implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'mac'
-    implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'linux'
-    implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'win'
-    implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'mac'
-    implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'linux'
-    implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'win'
-    implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'mac'
-    implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'linux'
-    implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'win'
-    implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'mac'
-    implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'linux'
+    // JavaFX dependencies are managed by the javafx {} block below
-plugins {
+plugins {
     id 'java'
     id 'application'
     id 'com.github.johnrengelman.shadow' version '7.1.2'
     id 'checkstyle'
+    id 'org.openjfx.javafxplugin' version '0.0.14'
 }

Add near the application block:

javafx {
    version = '17.0.7'
    modules = ['javafx.controls', 'javafx.fxml']
}

Optional: pin toolchain to 17 for consistency with JavaFX 17.

java {
  toolchain { languageVersion = JavaLanguageVersion.of(17) }
}
🤖 Prompt for AI Agents
In build.gradle around lines 15-28, remove the per-OS javafx implementation
dependencies (the win/mac/linux classifier lines) and instead apply the OpenJFX
Gradle plugin and declare the javafx configuration in the application block so
platform artifacts are resolved at build/run time; add a javafx block setting
version = '17.0.7' and modules = ['javafx.controls','javafx.fxml'], and
optionally pin the Java toolchain to Java 17 (java.toolchain languageVersion =
17) for consistency with JavaFX 17.

Comment thread build.gradle
Comment on lines 49 to +53
shadowJar {
archiveBaseName = "duke"
archiveBaseName = "serenity"
archiveClassifier = null
archiveFileName = 'serenity.jar'
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Set Main-Class in shaded JAR manifest.

Ensures java -jar serenity.jar runs without extra args.

 shadowJar {
     archiveBaseName = "serenity"
     archiveClassifier = null
     archiveFileName = 'serenity.jar'
+    manifest {
+        attributes 'Main-Class': 'serenity.gui.Launcher'
+    }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
shadowJar {
archiveBaseName = "duke"
archiveBaseName = "serenity"
archiveClassifier = null
archiveFileName = 'serenity.jar'
}
shadowJar {
archiveBaseName = "serenity"
archiveClassifier = null
archiveFileName = 'serenity.jar'
manifest {
attributes 'Main-Class': 'serenity.gui.Launcher'
}
}
🤖 Prompt for AI Agents
In build.gradle around lines 49–53, the shadowJar block doesn't set a Main-Class
in the JAR manifest so running "java -jar serenity.jar" fails; update the
shadowJar configuration to add a manifest entry "Main-Class" pointing to your
application's fully-qualified main class (e.g. com.yourorg.Main), ensuring the
application/mainClassName (or application.plugin) is set consistently, and
re-run the shadowJar task so the produced serenity.jar contains that Main-Class
manifest attribute.

Comment on lines +24 to +26
<property name="format" value="((//.*)|(\*.*))FIXME" />
<property name="message" value='TODO is preferred to FIXME."' />
</module>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix trailing quote in RegexpSingleline message.

There’s an extra double quote at the end.

-        <property name="message" value='TODO is preferred to FIXME."' />
+        <property name="message" value="TODO is preferred to FIXME." />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<property name="format" value="((//.*)|(\*.*))FIXME" />
<property name="message" value='TODO is preferred to FIXME."' />
</module>
<property name="format" value="((//.*)|(\*.*))FIXME" />
<property name="message" value="TODO is preferred to FIXME." />
</module>
🤖 Prompt for AI Agents
In config/checkstyle/checkstyle.xml around lines 24-26, the message attribute
value contains an extra trailing double quote (value='TODO is preferred to
FIXME."') — remove the stray double quote so the attribute reads value='TODO is
preferred to FIXME.' and ensure the XML attribute quoting remains consistent.

Comment on lines +8 to +9
<suppress checks="JavadocType" files=".*Test\.java"/>
<suppress checks="MissingJavadocMethodCheck" files=".*Test\.java"/>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix Checkstyle check name: use MissingJavadocMethod (without 'Check').

In SuppressionFilter, the check name should be the module’s simple name (e.g., MissingJavadocMethod), not the class name with the Check suffix.

Apply this diff:

     <suppress checks="JavadocType" files=".*Test\.java"/>
-    <suppress checks="MissingJavadocMethodCheck" files=".*Test\.java"/>
+    <suppress checks="MissingJavadocMethod" files=".*Test\.java"/>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<suppress checks="JavadocType" files=".*Test\.java"/>
<suppress checks="MissingJavadocMethodCheck" files=".*Test\.java"/>
<suppress checks="JavadocType" files=".*Test\.java"/>
<suppress checks="MissingJavadocMethod" files=".*Test\.java"/>
🤖 Prompt for AI Agents
In config/checkstyle/suppressions.xml around lines 8 to 9, the suppression uses
the incorrect Checkstyle module name "MissingJavadocMethodCheck"; update that
value to the module’s simple name "MissingJavadocMethod" (i.e., change the
checks attribute on the second suppress element from MissingJavadocMethodCheck
to MissingJavadocMethod) so SuppressionFilter matches correctly.

Comment thread docs/README.md
Comment on lines +31 to +36
Adds a deadline task to the task list.

Format: `deadline DESCRIPTION /from START /to END`

Examples:
- `event project meeting /from Monday 2pm /to 4pm`

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix command type: this section is about event, not deadline

Header text and format currently reference “deadline”.

-Adds a deadline task to the task list.
+Adds an event task to the task list.
@@
-Format: `deadline DESCRIPTION /from START /to END`
+Format: `event DESCRIPTION /from START /to END`
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Adds a deadline task to the task list.
Format: `deadline DESCRIPTION /from START /to END`
Examples:
- `event project meeting /from Monday 2pm /to 4pm`
Adds an event task to the task list.
Format: `event DESCRIPTION /from START /to END`
Examples:
- `event project meeting /from Monday 2pm /to 4pm`
🤖 Prompt for AI Agents
In docs/README.md around lines 31 to 36, the header and format incorrectly
reference "deadline" while the examples and section describe an event command;
change the header text and command format to refer to "event" (e.g., "Adds an
event task to the task list." and "Format: `event DESCRIPTION /from START /to
END`") and update any example phrasing if needed to consistently use "event"
instead of "deadline".

Comment on lines +62 to +74
@Test
public void changeStatus_missingIndex_exceptionThrown() {
ArrayList<Task> tasks = new ArrayList<>();
TaskList taskList = new TaskList(tasks);
Todo task = new Todo("read book");
taskList.addTask(task);
try {
taskList.changeStatus("mark ");
} catch (SerenityException e) {
assertEquals("Error: Missing index.",
e.getMessage());
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Refactor to assertThrows (missing index).

-        try {
-            taskList.changeStatus("mark ");
-        } catch (SerenityException e) {
-            assertEquals("Error: Missing index.",
-                    e.getMessage());
-        }
+        SerenityException e = assertThrows(SerenityException.class,
+                () -> taskList.changeStatus("mark "));
+        assertEquals("Error: Missing index.", e.getMessage());
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Test
public void changeStatus_missingIndex_exceptionThrown() {
ArrayList<Task> tasks = new ArrayList<>();
TaskList taskList = new TaskList(tasks);
Todo task = new Todo("read book");
taskList.addTask(task);
try {
taskList.changeStatus("mark ");
} catch (SerenityException e) {
assertEquals("Error: Missing index.",
e.getMessage());
}
}
@Test
public void changeStatus_missingIndex_exceptionThrown() {
ArrayList<Task> tasks = new ArrayList<>();
TaskList taskList = new TaskList(tasks);
Todo task = new Todo("read book");
taskList.addTask(task);
SerenityException e = assertThrows(SerenityException.class,
() -> taskList.changeStatus("mark "));
assertEquals("Error: Missing index.", e.getMessage());
}
🤖 Prompt for AI Agents
In src/test/java/serenity/TaskListTest.java around lines 62 to 74, the test
currently uses a try/catch to verify that calling taskList.changeStatus("mark ")
throws a SerenityException for a missing index; replace this pattern with
JUnit's assertThrows: call assertThrows(SerenityException.class, () ->
taskList.changeStatus("mark ")), capture the thrown exception, and assert its
message equals "Error: Missing index."; remove the try/catch and ensure imports
for assertThrows are available.

Comment on lines +76 to +88
@Test
public void changeStatus_invalidIndex_exceptionThrown() {
ArrayList<Task> tasks = new ArrayList<>();
TaskList taskList = new TaskList(tasks);
Todo task = new Todo("read book");
taskList.addTask(task);
try {
taskList.changeStatus("mark 2");
} catch (SerenityException e) {
assertEquals("Error: Index is out of bounds.",
e.getMessage());
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Refactor to assertThrows (invalid index).

-        try {
-            taskList.changeStatus("mark 2");
-        } catch (SerenityException e) {
-            assertEquals("Error: Index is out of bounds.",
-                    e.getMessage());
-        }
+        SerenityException e = assertThrows(SerenityException.class,
+                () -> taskList.changeStatus("mark 2"));
+        assertEquals("Error: Index is out of bounds.", e.getMessage());
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Test
public void changeStatus_invalidIndex_exceptionThrown() {
ArrayList<Task> tasks = new ArrayList<>();
TaskList taskList = new TaskList(tasks);
Todo task = new Todo("read book");
taskList.addTask(task);
try {
taskList.changeStatus("mark 2");
} catch (SerenityException e) {
assertEquals("Error: Index is out of bounds.",
e.getMessage());
}
}
@Test
public void changeStatus_invalidIndex_exceptionThrown() {
ArrayList<Task> tasks = new ArrayList<>();
TaskList taskList = new TaskList(tasks);
Todo task = new Todo("read book");
taskList.addTask(task);
SerenityException e = assertThrows(SerenityException.class,
() -> taskList.changeStatus("mark 2"));
assertEquals("Error: Index is out of bounds.", e.getMessage());
}
🤖 Prompt for AI Agents
In src/test/java/serenity/TaskListTest.java around lines 76 to 88, the test for
an invalid index currently uses a try/catch to assert the SerenityException;
refactor it to use JUnit's assertThrows to make the test clearer and fail
correctly on no exception. Replace the try/catch with a call to
assertThrows(SerenityException.class, () -> taskList.changeStatus("mark 2")) and
capture the thrown exception to assert its message equals "Error: Index is out
of bounds."; ensure the test imports static
org.junit.jupiter.api.Assertions.assertThrows (and assertEquals if not already).

Comment on lines +123 to +135
@Test
public void updateTask_missingIndex_exceptionThrown() {
ArrayList<Task> tasks = new ArrayList<>();
TaskList taskList = new TaskList(tasks);
Todo task = new Todo("read book");
taskList.addTask(task);
try {
taskList.updateTask("update /update todo read English Book");
} catch (SerenityException e) {
assertEquals("Error: Missing index.",
e.getMessage());
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Refactor to assertThrows (update missing index).

-        try {
-            taskList.updateTask("update /update todo read English Book");
-        } catch (SerenityException e) {
-            assertEquals("Error: Missing index.",
-                    e.getMessage());
-        }
+        SerenityException e = assertThrows(SerenityException.class,
+                () -> taskList.updateTask("update /update todo read English Book"));
+        assertEquals("Error: Missing index.", e.getMessage());
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Test
public void updateTask_missingIndex_exceptionThrown() {
ArrayList<Task> tasks = new ArrayList<>();
TaskList taskList = new TaskList(tasks);
Todo task = new Todo("read book");
taskList.addTask(task);
try {
taskList.updateTask("update /update todo read English Book");
} catch (SerenityException e) {
assertEquals("Error: Missing index.",
e.getMessage());
}
}
@Test
public void updateTask_missingIndex_exceptionThrown() {
ArrayList<Task> tasks = new ArrayList<>();
TaskList taskList = new TaskList(tasks);
Todo task = new Todo("read book");
taskList.addTask(task);
- try {
- taskList.updateTask("update /update todo read English Book");
- } catch (SerenityException e) {
- assertEquals("Error: Missing index.",
- e.getMessage());
SerenityException e = assertThrows(SerenityException.class,
() -> taskList.updateTask("update /update todo read English Book"));
assertEquals("Error: Missing index.", e.getMessage());
}
🤖 Prompt for AI Agents
In src/test/java/serenity/TaskListTest.java around lines 123 to 135, the test
for updateTask_missingIndex currently uses a try/catch to verify the
SerenityException; replace this with JUnit's assertThrows to make the test
clearer and more idiomatic: call assertThrows(SerenityException.class, () ->
taskList.updateTask("update /update todo read English Book")) and assert the
exception message equals "Error: Missing index." using the returned exception's
getMessage(), removing the try/catch block and the manual fail path.

Comment on lines +137 to +149
@Test
public void updateTask_invalidIndex_exceptionThrown() {
ArrayList<Task> tasks = new ArrayList<>();
TaskList taskList = new TaskList(tasks);
Todo task = new Todo("read book");
taskList.addTask(task);
try {
taskList.updateTask("update 2 /update todo read English Book");
} catch (SerenityException e) {
assertEquals("Error: Index is out of bounds.",
e.getMessage());
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Refactor to assertThrows (update invalid index).

-        try {
-            taskList.updateTask("update 2 /update todo read English Book");
-        } catch (SerenityException e) {
-            assertEquals("Error: Index is out of bounds.",
-                    e.getMessage());
-        }
+        SerenityException e = assertThrows(SerenityException.class,
+                () -> taskList.updateTask("update 2 /update todo read English Book"));
+        assertEquals("Error: Index is out of bounds.", e.getMessage());
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Test
public void updateTask_invalidIndex_exceptionThrown() {
ArrayList<Task> tasks = new ArrayList<>();
TaskList taskList = new TaskList(tasks);
Todo task = new Todo("read book");
taskList.addTask(task);
try {
taskList.updateTask("update 2 /update todo read English Book");
} catch (SerenityException e) {
assertEquals("Error: Index is out of bounds.",
e.getMessage());
}
}
@Test
public void updateTask_invalidIndex_exceptionThrown() {
ArrayList<Task> tasks = new ArrayList<>();
TaskList taskList = new TaskList(tasks);
Todo task = new Todo("read book");
taskList.addTask(task);
SerenityException e = assertThrows(SerenityException.class,
() -> taskList.updateTask("update 2 /update todo read English Book"));
assertEquals("Error: Index is out of bounds.", e.getMessage());
}
🤖 Prompt for AI Agents
In src/test/java/serenity/TaskListTest.java around lines 137 to 149, the test
uses a try-catch to verify an invalid-index SerenityException; replace this with
JUnit's assertThrows to make the test clearer and fail on no exception: call
assertThrows(SerenityException.class, () -> taskList.updateTask("update 2
/update todo read English Book")) and then assertEquals the expected message
against the thrown exception's getMessage(); remove the try-catch and any
unreachable code so the test fails if no exception is thrown.

Comment thread text-ui-test/runtest.bat

REM run the program, feed commands from input.txt file and redirect the output to the ACTUAL.TXT
java -classpath ..\bin Duke < input.txt > ACTUAL.TXT
java -classpath ..\bin Serenity < input.txt > ACTUAL.TXT

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Run the correct fully-qualified main class

Serenity is packaged; invoking the simple name will fail with “Could not find or load main class”.

-java -classpath ..\bin Serenity < input.txt > ACTUAL.TXT
+java -classpath ..\bin serenity.Serenity < input.txt > ACTUAL.TXT

Verification (checks class/package and presence of a main):


🏁 Script executed:

#!/bin/bash
# Verify Serenity main class is packaged and has a main method
rg -nC2 '^\s*package\s+serenity\b' src/main/java/serenity/Serenity.java
rg -nC1 'public\s+static\s+void\s+main\s*\(' src/main/java/serenity/Serenity.java

Length of output: 321


Use fully-qualified class name in runtest.bat

Replace the invocation on line 18 of text-ui-test/runtest.bat:

-java -classpath ..\bin Serenity < input.txt > ACTUAL.TXT
+java -classpath ..\bin serenity.Serenity < input.txt > ACTUAL.TXT

This matches package serenity; and the public static void main(String[] args) in src/main/java/serenity/Serenity.java.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
java -classpath ..\bin Serenity < input.txt > ACTUAL.TXT
java -classpath ..\bin serenity.Serenity < input.txt > ACTUAL.TXT
🤖 Prompt for AI Agents
In text-ui-test/runtest.bat around line 18, replace the invocation that calls
the class without its package with the fully-qualified class name; specifically
update the java command to invoke serenity.Serenity (matching package serenity
and the main class Serenity) so it runs: java -classpath ..\bin
serenity.Serenity < input.txt > ACTUAL.TXT.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant