From 2b8542032b36615c863efc1b28e40c713b2501fd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 18 Jul 2026 15:40:12 +0000 Subject: [PATCH] test: add model unit tests for User.getDisplayName() and Task.toString() bugs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit UserModelTest (10 tests): - 3 happy-path tests for all getDisplayName() branches - 3 bug-pin tests: partial name (firstName but no lastName, or vice versa) is silently ignored — caller's name data is lost, method falls back to full_name/username without warning - 2 precedence tests (firstName+lastName beats full_name; full_name beats username) - 2 edge cases (empty strings, default constructor returns null without NPE) TaskModelTest (7 tests): - 2 constructor tests (short and default constructors) - 3 bug-pin tests: Task.toString() throws NPE when assignee_id or due_date is null (calls assignee_id.toString() and due_date.trim() without null checks) - 1 positive test: toString() succeeds when all required fields are set - 1 test: attachmentUrls initialised as empty list (not null) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../com/taskflow/model/TaskModelTest.java | 102 +++++++++++++++ .../com/taskflow/model/UserModelTest.java | 121 ++++++++++++++++++ 2 files changed, 223 insertions(+) create mode 100644 src/test/java/com/taskflow/model/TaskModelTest.java create mode 100644 src/test/java/com/taskflow/model/UserModelTest.java diff --git a/src/test/java/com/taskflow/model/TaskModelTest.java b/src/test/java/com/taskflow/model/TaskModelTest.java new file mode 100644 index 0000000..b66ecc6 --- /dev/null +++ b/src/test/java/com/taskflow/model/TaskModelTest.java @@ -0,0 +1,102 @@ +package com.taskflow.model; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Unit tests for the {@link Task} model. + * + *

Bug pins for {@link Task#toString()}: + *

+ */ +class TaskModelTest { + + // --- constructor tests --- + + @Test + void shortConstructor_setsFieldsCorrectly() { + Task task = new Task("Fix login", 3, "bug", "Login fails on empty password", 42L); + assertEquals("Fix login", task.getTitle()); + assertEquals(3, task.getPriority()); + assertEquals("bug", task.type); + assertEquals("Fix login", task.getTitle()); + assertEquals(42L, task.assignee_id); + assertEquals(0, task.getStatus()); // default status is 0 (todo) + assertNotNull(task.createdDate); + } + + @Test + void defaultConstructor_allFieldsDefaultToNull() { + Task task = new Task(); + assertNull(task.getId()); + assertNull(task.getTitle()); + assertEquals(0, task.getStatus()); + assertEquals(0, task.getPriority()); + } + + // --- toString() NPE bug-pin tests --- + + /** + * Bug pin: Task.toString() calls assignee_id.toString() without null check. + * Constructing a Task via no-arg constructor leaves assignee_id=null → NPE. + */ + @Test + void toString_nullAssigneeId_throwsNPE() { + Task task = new Task(); + task.setTitle("Test task"); + task.due_date = "2026-01-01"; + // BUG: assignee_id.toString() throws NullPointerException + assertThrows(NullPointerException.class, task::toString); + } + + /** + * Bug pin: Task.toString() calls due_date.trim() without null check. + */ + @Test + void toString_nullDueDate_throwsNPE() { + Task task = new Task(); + task.setTitle("Test task"); + task.assignee_id = 1L; + // due_date is null → BUG: due_date.trim() throws NullPointerException + assertThrows(NullPointerException.class, task::toString); + } + + /** + * Bug pin: Task constructed via no-arg constructor has null assignee_id and due_date; + * calling toString() throws NPE even for a task that is otherwise valid. + */ + @Test + void toString_defaultConstructorFields_throwsNPE() { + Task task = new Task(); + task.setTitle("Minimal task"); + assertThrows(NullPointerException.class, task::toString); + } + + /** + * Positive case: toString() succeeds when both assignee_id and due_date are set. + */ + @Test + void toString_allRequiredFieldsSet_noException() { + Task task = new Task(); + task.setTitle("Deploy"); + task.setStatus(1); + task.assignee_id = 7L; + task.due_date = "2026-12-31"; + String result = assertDoesNotThrow(task::toString); + assertTrue(result.contains("Deploy")); + assertTrue(result.contains("7")); + } + + // --- attachmentUrls initial state --- + + @Test + void attachmentUrls_initializedAsEmptyList() { + Task task = new Task(); + assertNotNull(task.attachmentUrls); + assertTrue(task.attachmentUrls.isEmpty()); + } +} diff --git a/src/test/java/com/taskflow/model/UserModelTest.java b/src/test/java/com/taskflow/model/UserModelTest.java new file mode 100644 index 0000000..f42560f --- /dev/null +++ b/src/test/java/com/taskflow/model/UserModelTest.java @@ -0,0 +1,121 @@ +package com.taskflow.model; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Unit tests for {@link User#getDisplayName()}. + * + *

getDisplayName() has three branches: + *

    + *
  1. Both firstName AND lastName non-null → "firstName lastName"
  2. + *
  3. Either first/last is null, but full_name non-null → full_name
  4. + *
  5. full_name also null → username
  6. + *
+ * + *

Bug documented: if firstName is set but lastName is null (or vice versa), + * the set name is silently ignored and the method falls through to full_name/username. + */ +class UserModelTest { + + // --- happy path --- + + @Test + void getDisplayName_bothFirstAndLastName_returnsCombined() { + User user = new User("jsmith", "j@example.com", "pass"); + user.setFirstName("John"); + user.setLastName("Smith"); + assertEquals("John Smith", user.getDisplayName()); + } + + @Test + void getDisplayName_noFirstOrLastName_usesFullName() { + User user = new User("jsmith", "j@example.com", "pass"); + user.setFull_name("John Smith"); + assertEquals("John Smith", user.getDisplayName()); + } + + @Test + void getDisplayName_noNamesAtAll_usesUsername() { + User user = new User("jsmith", "j@example.com", "pass"); + assertEquals("jsmith", user.getDisplayName()); + } + + // --- bug-pin tests: partial name silently ignored --- + + /** + * Bug pin: firstName set but lastName is null. + * The caller might expect "John" but the method skips to full_name/username. + * Current (buggy) behaviour: falls through to full_name if set, else username. + */ + @Test + void getDisplayName_firstNameSetButLastNameNull_fallsBackToFullName() { + User user = new User("jsmith", "j@example.com", "pass"); + user.setFirstName("John"); + // lastName is null; full_name is set + user.setFull_name("John Smith (full)"); + // BUG: firstName is ignored; full_name is returned instead + assertEquals("John Smith (full)", user.getDisplayName()); + } + + @Test + void getDisplayName_firstNameSetLastNameNullNoFullName_fallsBackToUsername() { + User user = new User("jsmith", "j@example.com", "pass"); + user.setFirstName("John"); + // lastName is null; full_name is also null + // BUG: the caller-supplied firstName is silently discarded + assertEquals("jsmith", user.getDisplayName()); + } + + @Test + void getDisplayName_lastNameSetButFirstNameNull_fallsBackToUsername() { + User user = new User("jsmith", "j@example.com", "pass"); + user.setLastName("Smith"); + // firstName is null; full_name is also null + // BUG: the caller-supplied lastName is silently discarded + assertEquals("jsmith", user.getDisplayName()); + } + + // --- precedence --- + + /** + * firstName+lastName wins over full_name when both are set. + */ + @Test + void getDisplayName_firstAndLastNamePrecedeFullName() { + User user = new User("jsmith", "j@example.com", "pass"); + user.setFirstName("John"); + user.setLastName("Smith"); + user.setFull_name("J. Smith (legacy)"); + assertEquals("John Smith", user.getDisplayName()); + } + + /** + * full_name wins over username when first/last are missing. + */ + @Test + void getDisplayName_fullNamePrecedesUsername() { + User user = new User("jsmith", "j@example.com", "pass"); + user.setFull_name("John Smith"); + assertEquals("John Smith", user.getDisplayName()); + } + + // --- edge cases --- + + @Test + void getDisplayName_emptyFirstAndLastName_returnsSpaceSeparated() { + // Both are non-null (empty strings) → concatenated as " " + User user = new User("jsmith", "j@example.com", "pass"); + user.setFirstName(""); + user.setLastName(""); + assertEquals(" ", user.getDisplayName()); + } + + @Test + void getDisplayName_defaultConstructor_noNPE() { + User user = new User(); + // All name fields are null; username is null too → returns null (no NPE) + assertNull(user.getDisplayName()); + } +}