From bfaccd1f3fa5a69e852a243c74389a39adee8aac Mon Sep 17 00:00:00 2001 From: Andre Velkov Janusev Date: Thu, 14 Aug 2025 14:40:27 +0200 Subject: [PATCH 1/5] Red Stage complete, tasks done and failing. --- .../java/com/booleanuk/core/TodoList.java | 46 ++++++ .../java/com/booleanuk/core/domain-model.md | 16 ++ .../java/com/booleanuk/core/TodoListTest.java | 153 +++++++++++++++++- 3 files changed, 211 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/booleanuk/core/domain-model.md diff --git a/src/main/java/com/booleanuk/core/TodoList.java b/src/main/java/com/booleanuk/core/TodoList.java index 675adaf0b..6341cb1c4 100644 --- a/src/main/java/com/booleanuk/core/TodoList.java +++ b/src/main/java/com/booleanuk/core/TodoList.java @@ -1,5 +1,51 @@ package com.booleanuk.core; +import java.util.ArrayList; +import java.util.HashMap; + public class TodoList { + HashMap todoMap = new HashMap<>(); + + public TodoList(HashMap map) { + this.todoMap = map; + } + + public Boolean add(String name) { + + return null; + } + + public HashMap getAll() { + return HashMap.newHashMap(0); + } + + public ArrayList getCompletedTasks() { + return new ArrayList<>(); + } + + public ArrayList getIncompleteTasks() { + return new ArrayList<>(); + } + + public Boolean toggleStatus(String taskName) { + + return false; + } + + public String searchForTask(String taskName) { + + return ""; + } + + public void removeTask(String task) { + + } + + public HashMap getAllAscending() { + return HashMap.newHashMap(0); + } + public HashMap getAllDescending() { + return HashMap.newHashMap(0); + } } diff --git a/src/main/java/com/booleanuk/core/domain-model.md b/src/main/java/com/booleanuk/core/domain-model.md new file mode 100644 index 000000000..55454a984 --- /dev/null +++ b/src/main/java/com/booleanuk/core/domain-model.md @@ -0,0 +1,16 @@ + + +| **Class** | **Members** | **Methods** | **Scenario** | **Outputs** | +| ---------- | ------------------------------------ | -------------------------------------- |--------------------------------------------------------------------------------|----------------------------| +| `TodoList` | `HashMap todoMap` | `add(String name)` | Task is not in the list | `true` | +| | | | Task with same name already exists | `false` | +| | | `getAll()` | List contains tasks | `HashMap` | +| | | `getCompleted()` | Some tasks are marked as complete | `HashMap` | +| | | `getIncomplete()` | Some tasks are incomplete | `HashMap` | +| | | `toggleStatus(String name)` | Task with that name exists — changes from incomplete to complete or vice versa | `true` / `false` | +| | | `search(String name)` | Task with that name exists | `"Task found"` | +| | | | Task does not exist | `"Task not found"` | +| | | `remove(String name)` | Task removed from list | `true` | +| | | | Task does not exist | `false` | +| | | `getAllAsc()` | Returns all tasks sorted by name A–Z | `HashMap` | +| | | `getAllDesc()` | Returns all tasks sorted Z–A | `HashMap` | diff --git a/src/test/java/com/booleanuk/core/TodoListTest.java b/src/test/java/com/booleanuk/core/TodoListTest.java index 0bef779a4..4b03e0f60 100644 --- a/src/test/java/com/booleanuk/core/TodoListTest.java +++ b/src/test/java/com/booleanuk/core/TodoListTest.java @@ -3,11 +3,156 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import java.util.HashMap; +import java.util.List; + class TodoListTest { + private HashMap testmap = null; + + public void loadTasks() { + testmap = new HashMap<>(); + testmap.put("Task1", false); + testmap.put("Task2", false); + testmap.put("Task3", true); + testmap.put("Task4", false); + testmap.put("Task5", true); + } + + @Test + public void addTaskThatAlreadyExists() { + loadTasks(); + TodoList list = new TodoList(testmap); + + Assertions.assertFalse(list.add("Task1")); + Assertions.assertFalse(list.add("Task2")); + Assertions.assertTrue(list.add("Task1")); + Assertions.assertFalse(list.add("Task5")); + Assertions.assertTrue(list.add("Task2")); + } + + @Test + public void addTaskWithNameWhichAlreadyExists() { + loadTasks(); + TodoList list = new TodoList(testmap); + Assertions.assertTrue(list.add("Task1")); + Assertions.assertFalse(list.add("Task11")); + Assertions.assertTrue(list.add("task1")); // Case-sensitive + Assertions.assertFalse(list.add(" ")); + } + + @Test + public void getAllTasksReturnsMapOrEmptyMapIfNoContent() { + // Test on Empty + TodoList list = new TodoList(HashMap.newHashMap(0)); + Assertions.assertEquals(0, list.getAll().size()); + loadTasks(); + TodoList list2 = new TodoList(testmap); + Assertions.assertEquals(5, list2.getAll().size()); + list.add("item6"); + Assertions.assertEquals(6, list2.getAll().size()); + } + + @Test + public void getCompletedTasks() { + loadTasks(); + TodoList list = new TodoList(testmap); + + Assertions.assertEquals(2, list.getCompletedTasks().size()); + list.add("task25"); + Assertions.assertEquals(2, list.getCompletedTasks().size()); + } + + @Test + public void getIncompleteTasks() { + loadTasks(); + TodoList list = new TodoList(testmap); + + Assertions.assertEquals(3, list.getIncompleteTasks().size()); + list.add("task25"); + Assertions.assertEquals(4, list.getCompletedTasks().size()); + } + + @Test + public void toggleTaskStatus() { + loadTasks(); + TodoList list = new TodoList(testmap); + + Assertions.assertTrue(list.toggleStatus("task1")); + Assertions.assertFalse(list.toggleStatus("task500")); //task do not exist + Assertions.assertFalse(list.toggleStatus(" ")); + } + + @Test + public void searchForTaskWhichExists() { + loadTasks(); + TodoList list = new TodoList(testmap); + Assertions.assertEquals("Task found.", list.searchForTask("task2")); + Assertions.assertEquals("Task found.", list.searchForTask("task5")); + Assertions.assertEquals("Task found.", list.searchForTask("Task5")); + } + @Test - public void exampleTest() { - String hello = "Hello"; - Assertions.assertEquals("Hello", hello); - Assertions.assertNotEquals("Goodbye", hello); + public void searchForTaskThatDoesNotExist() { + loadTasks(); + TodoList list = new TodoList(testmap); + Assertions.assertEquals("Task not found.", list.searchForTask("task22")); + Assertions.assertEquals("Task not found.", list.searchForTask("task5515")); + Assertions.assertEquals("Task not found.", list.searchForTask("task")); + Assertions.assertEquals("Task not found.", list.searchForTask(" ")); } + + @Test + public void removeTaskWhichExists() { + loadTasks(); + TodoList list = new TodoList(testmap); + Assertions.assertEquals(5, list.getAll().size()); + list.removeTask("task2"); + Assertions.assertEquals(4, list.getAll().size()); + list.removeTask("task1"); + Assertions.assertEquals(3, list.getAll().size()); + list.removeTask("task5"); + list.removeTask("task4"); + Assertions.assertEquals(1, list.getAll().size()); + } + + @Test + public void removeTaskThatDoNotExist() { + loadTasks(); + TodoList list = new TodoList(testmap); + + list.removeTask("task2"); + Assertions.assertEquals(4, list.getAll().size()); + list.removeTask("task10"); + Assertions.assertEquals(4, list.getAll().size()); + list.removeTask(""); + Assertions.assertEquals(4, list.getAll().size()); + list.removeTask(" "); + Assertions.assertEquals(4, list.getAll().size()); + } + + @Test + public void getTasksInAscendingOrder() { + testmap = new HashMap<>(); + testmap.put("b", false); + testmap.put("d", false); + testmap.put("c", false); + testmap.put("a", false); + TodoList list = new TodoList(testmap); + + Assertions.assertEquals(List.of("a", "b", "c", "d"), list.getAllAscending()); + } + + @Test + public void getTasksInDescendingOrder() { + testmap = new HashMap<>(); + testmap.put("b", false); + testmap.put("d", false); + testmap.put("c", false); + testmap.put("a", false); + TodoList list = new TodoList(testmap); + + Assertions.assertEquals(List.of("d", "c", "b", "a"), list.getAllDescending()); + } + + } From faa443892c50f98b6c45f2ccaad9cabe4a1a3617 Mon Sep 17 00:00:00 2001 From: Andre Velkov Janusev Date: Thu, 14 Aug 2025 15:35:42 +0200 Subject: [PATCH 2/5] Green Stage complete, tests passing. --- .../java/com/booleanuk/core/TodoList.java | 66 +++++++++++++++---- .../java/com/booleanuk/core/TodoListTest.java | 35 +++++----- 2 files changed, 71 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/booleanuk/core/TodoList.java b/src/main/java/com/booleanuk/core/TodoList.java index 6341cb1c4..7b1437db8 100644 --- a/src/main/java/com/booleanuk/core/TodoList.java +++ b/src/main/java/com/booleanuk/core/TodoList.java @@ -1,7 +1,9 @@ package com.booleanuk.core; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; +import java.util.Map; public class TodoList { HashMap todoMap = new HashMap<>(); @@ -10,42 +12,80 @@ public TodoList(HashMap map) { this.todoMap = map; } - public Boolean add(String name) { + public Boolean add(String task) { + if (task.toLowerCase().trim().isEmpty()) { + return false; + } + if (todoMap.containsKey(task.toLowerCase().trim())) { + return false; + } - return null; + todoMap.put(task, false); + return true; } public HashMap getAll() { - return HashMap.newHashMap(0); + return todoMap; } public ArrayList getCompletedTasks() { - return new ArrayList<>(); + ArrayList completedTasks = new ArrayList<>(); + + for (Map.Entry entry : todoMap.entrySet()) + if (entry.getValue().equals(true)) + completedTasks.add(entry.getKey()); + + return completedTasks; } public ArrayList getIncompleteTasks() { - return new ArrayList<>(); + ArrayList incompleteTasks = new ArrayList<>(); + + for (Map.Entry entry : todoMap.entrySet()) + if (entry.getValue().equals(false)) + incompleteTasks.add(entry.getKey()); + + return incompleteTasks; } public Boolean toggleStatus(String taskName) { - + for (Map.Entry entry : todoMap.entrySet()) + if (entry.getKey().equals(taskName.toLowerCase().trim())) { + boolean value = entry.getValue(); + entry.setValue(!value); + return true; + } return false; } public String searchForTask(String taskName) { - - return ""; + for (Map.Entry entry : todoMap.entrySet()) + if (entry.getKey().equals(taskName.toLowerCase().trim())) + return "Task found."; + return "Task not found."; } public void removeTask(String task) { - + for (Map.Entry entry : todoMap.entrySet()) + if (entry.getKey().equals(task.toLowerCase().trim())) { + todoMap.remove(entry.getKey()); + return; + } } - public HashMap getAllAscending() { - return HashMap.newHashMap(0); + // Can use TreeMap as return ?? + public ArrayList getAllAscending() { + ArrayList keyList = new ArrayList<>(todoMap.keySet()); + keyList.sort(null); + + return keyList; } - public HashMap getAllDescending() { - return HashMap.newHashMap(0); + public ArrayList getAllDescending() { + ArrayList keyList = new ArrayList<>(todoMap.keySet()); + keyList.sort(null); + Collections.reverse(keyList); + + return keyList; } } diff --git a/src/test/java/com/booleanuk/core/TodoListTest.java b/src/test/java/com/booleanuk/core/TodoListTest.java index 4b03e0f60..4ec39483f 100644 --- a/src/test/java/com/booleanuk/core/TodoListTest.java +++ b/src/test/java/com/booleanuk/core/TodoListTest.java @@ -11,44 +11,46 @@ class TodoListTest { public void loadTasks() { testmap = new HashMap<>(); - testmap.put("Task1", false); - testmap.put("Task2", false); - testmap.put("Task3", true); - testmap.put("Task4", false); - testmap.put("Task5", true); + testmap.put("task1", false); + testmap.put("task2", false); + testmap.put("task3", true); + testmap.put("task4", false); + testmap.put("task5", true); } @Test - public void addTaskThatAlreadyExists() { + public void addTaskThatDoesNotExist() { loadTasks(); TodoList list = new TodoList(testmap); Assertions.assertFalse(list.add("Task1")); Assertions.assertFalse(list.add("Task2")); - Assertions.assertTrue(list.add("Task1")); + Assertions.assertFalse(list.add("task2")); + Assertions.assertTrue(list.add("Task10")); Assertions.assertFalse(list.add("Task5")); - Assertions.assertTrue(list.add("Task2")); + Assertions.assertTrue(list.add("Task20")); + Assertions.assertFalse(list.add(" ")); } @Test - public void addTaskWithNameWhichAlreadyExists() { + public void addTaskThatAlreadyExists() { loadTasks(); TodoList list = new TodoList(testmap); - Assertions.assertTrue(list.add("Task1")); - Assertions.assertFalse(list.add("Task11")); - Assertions.assertTrue(list.add("task1")); // Case-sensitive + Assertions.assertFalse(list.add("Task1")); + Assertions.assertTrue(list.add("Task11")); + Assertions.assertFalse(list.add("task1")); // Case-sensitive Assertions.assertFalse(list.add(" ")); } @Test public void getAllTasksReturnsMapOrEmptyMapIfNoContent() { - // Test on Empty TodoList list = new TodoList(HashMap.newHashMap(0)); - Assertions.assertEquals(0, list.getAll().size()); + Assertions.assertEquals(0, list.getAll().size()); // Test on Empty + loadTasks(); TodoList list2 = new TodoList(testmap); Assertions.assertEquals(5, list2.getAll().size()); - list.add("item6"); + list2.add("item6"); Assertions.assertEquals(6, list2.getAll().size()); } @@ -69,7 +71,7 @@ public void getIncompleteTasks() { Assertions.assertEquals(3, list.getIncompleteTasks().size()); list.add("task25"); - Assertions.assertEquals(4, list.getCompletedTasks().size()); + Assertions.assertEquals(4, list.getIncompleteTasks().size()); } @Test @@ -154,5 +156,4 @@ public void getTasksInDescendingOrder() { Assertions.assertEquals(List.of("d", "c", "b", "a"), list.getAllDescending()); } - } From f176658debede29049b56ca20cf6f494c460ab3d Mon Sep 17 00:00:00 2001 From: Andre Velkov Janusev Date: Thu, 14 Aug 2025 15:39:55 +0200 Subject: [PATCH 3/5] Blue Stage complete. --- src/main/java/com/booleanuk/core/TodoList.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/booleanuk/core/TodoList.java b/src/main/java/com/booleanuk/core/TodoList.java index 7b1437db8..f8aa0921d 100644 --- a/src/main/java/com/booleanuk/core/TodoList.java +++ b/src/main/java/com/booleanuk/core/TodoList.java @@ -15,8 +15,7 @@ public TodoList(HashMap map) { public Boolean add(String task) { if (task.toLowerCase().trim().isEmpty()) { return false; - } - if (todoMap.containsKey(task.toLowerCase().trim())) { + } else if (todoMap.containsKey(task.toLowerCase().trim())) { return false; } @@ -51,8 +50,7 @@ public ArrayList getIncompleteTasks() { public Boolean toggleStatus(String taskName) { for (Map.Entry entry : todoMap.entrySet()) if (entry.getKey().equals(taskName.toLowerCase().trim())) { - boolean value = entry.getValue(); - entry.setValue(!value); + entry.setValue(!entry.getValue()); return true; } return false; @@ -77,7 +75,6 @@ public void removeTask(String task) { public ArrayList getAllAscending() { ArrayList keyList = new ArrayList<>(todoMap.keySet()); keyList.sort(null); - return keyList; } From 6781bd4dfea4de1178d19cd66bcc7bb8dacb781c Mon Sep 17 00:00:00 2001 From: Andre Velkov Janusev Date: Thu, 14 Aug 2025 16:39:03 +0200 Subject: [PATCH 4/5] Extensions, red stage complete -> test written and failing successfully :) --- .../java/com/booleanuk/extension/Task.java | 72 +++++++++++++++++++ .../extension/TodoListExtension.java | 37 ++++++++++ .../extension/TodoListExtensionTest.java | 53 ++++++++++++++ 3 files changed, 162 insertions(+) create mode 100644 src/main/java/com/booleanuk/extension/Task.java create mode 100644 src/main/java/com/booleanuk/extension/TodoListExtension.java create mode 100644 src/test/java/com/booleanuk/extension/TodoListExtensionTest.java diff --git a/src/main/java/com/booleanuk/extension/Task.java b/src/main/java/com/booleanuk/extension/Task.java new file mode 100644 index 000000000..ebe740457 --- /dev/null +++ b/src/main/java/com/booleanuk/extension/Task.java @@ -0,0 +1,72 @@ +package com.booleanuk.extension; + +import java.time.LocalDateTime; +import java.util.Date; + +public class Task { + private int id; + private String name; + private Date creationTime; + private Boolean status; + + public Task(int id, String name, Boolean status) { + this.id = id; + this.name = name; + this.creationTime = getRandomDate(); + this.status = status; + } + + public Date getRandomDate() { + long currentTime = System.currentTimeMillis(); + // Define time range: last year (365 days) + long yearInMillis = 365L * 24 * 60 * 60 * 1000; + long randomTime = currentTime - (long)(Math.random() * yearInMillis); + return new Date(randomTime); + } + + public Task() { + + } + + public Boolean getStatus() { + return status; + } + + public void setStatus(Boolean status) { + this.status = status; + } + + public void toggleStatus() { + this.status = !status; + } + + public Date getCreationTime() { + return creationTime; + } + + public void setCreationTime(Date creationTime) { + this.creationTime = creationTime; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } +} + +// +//I want to be able to get a task by a unique ID. +//I want to update the name of a task by providing its ID and a new name. +//I want to be able to change the status of a task by providing its ID. +//I want to be able to see the date and time that I created each task. \ No newline at end of file diff --git a/src/main/java/com/booleanuk/extension/TodoListExtension.java b/src/main/java/com/booleanuk/extension/TodoListExtension.java new file mode 100644 index 000000000..d9dd290ee --- /dev/null +++ b/src/main/java/com/booleanuk/extension/TodoListExtension.java @@ -0,0 +1,37 @@ +package com.booleanuk.extension; + +import java.util.ArrayList; +import java.util.HashMap; + +public class TodoListExtension { + ArrayList taskList = new ArrayList<>(); + + public TodoListExtension() { + taskList.add(new Task(1, "task1", false)); + taskList.add(new Task(2, "task2", false)); + taskList.add(new Task(3, "task3", false)); + taskList.add(new Task(4, "task4", false)); + } + + public void addTask(Task newTask) { + taskList.add(newTask); + } + + public Task getTaskByID(int id) { + + return null; + } + + public void updateTask(int id, String newName) { + + } + + public void changeStatusWithId(int id) { + + } + + public Task getTaskCreationTime(String taskName) { + + return null; + } +} diff --git a/src/test/java/com/booleanuk/extension/TodoListExtensionTest.java b/src/test/java/com/booleanuk/extension/TodoListExtensionTest.java new file mode 100644 index 000000000..11af8a24d --- /dev/null +++ b/src/test/java/com/booleanuk/extension/TodoListExtensionTest.java @@ -0,0 +1,53 @@ +package com.booleanuk.extension; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TodoListExtensionTest { + + @Test + public void addTaskSuccessfully() { + TodoListExtension todo = new TodoListExtension(); + Task newTask = new Task(5, "task5", false); + todo.addTask(newTask); + Assertions.assertEquals("task5", todo.getTaskByID(5).getName()); + } + + @Test + public void getTaskByIdElseNotFoundResponse() { + TodoListExtension todo = new TodoListExtension(); + Assertions.assertEquals(1, todo.getTaskByID(1).getId()); + Task task2 = todo.getTaskByID(10); + Assertions.assertNull(task2); + } + + @Test + public void updateTaskByIdAndName() { + TodoListExtension todo = new TodoListExtension(); + + Assertions.assertEquals("task2", todo.getTaskByID(2).getName()); + todo.updateTask(2, "test new name"); + Assertions.assertEquals("test new name", todo.getTaskByID(2).getName()); + } + + @Test + public void updateNonExistentTaskDoesNothing() { + TodoListExtension todo = new TodoListExtension(); + todo.updateTask(99, "newTask"); + Assertions.assertNull(todo.getTaskByID(99)); + } + + @Test + public void changeStatusByTaskId() { + TodoListExtension todo = new TodoListExtension(); + + Assertions.assertFalse(todo.getTaskByID(3).getStatus()); + todo.changeStatusWithId(3); + Assertions.assertTrue(todo.getTaskByID(3).getStatus()); + todo.changeStatusWithId(3); + Assertions.assertFalse(todo.getTaskByID(3).getStatus()); + todo.changeStatusWithId(4); + Assertions.assertTrue(todo.getTaskByID(4).getStatus()); + } + +} From 9596811da1e5ae51ece6de23f728f8dd519b8c53 Mon Sep 17 00:00:00 2001 From: Andre Velkov Janusev Date: Thu, 14 Aug 2025 16:54:18 +0200 Subject: [PATCH 5/5] Extensions complete --- .../extension/TodoListExtension.java | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/booleanuk/extension/TodoListExtension.java b/src/main/java/com/booleanuk/extension/TodoListExtension.java index d9dd290ee..f31a65bc3 100644 --- a/src/main/java/com/booleanuk/extension/TodoListExtension.java +++ b/src/main/java/com/booleanuk/extension/TodoListExtension.java @@ -1,6 +1,7 @@ package com.booleanuk.extension; import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; public class TodoListExtension { @@ -18,20 +19,34 @@ public void addTask(Task newTask) { } public Task getTaskByID(int id) { - + for (Task task : taskList) { + if (task.getId() == id) { + return task; + } + } return null; } public void updateTask(int id, String newName) { - + for (Task task : taskList) + if (task.getId() == id) + task.setName(newName); } public void changeStatusWithId(int id) { - + taskList.stream() + .filter(task -> task.getId() == id) + .findFirst().map(task -> {task.toggleStatus(); + return null; + }); } - public Task getTaskCreationTime(String taskName) { - + public Date getTaskCreationTime(String taskName) { + for (Task task : taskList) { + if (task.getName().equals(taskName)) { + return task.getCreationTime(); + } + } return null; } }