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()); + } +}