From 5f6d8e5c464a835addb1f014ebfb05b0a297f8ed Mon Sep 17 00:00:00 2001 From: Aleksey Gurzhiev Date: Sat, 23 Nov 2024 12:59:35 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A1=D0=B4=D0=B5=D0=BB=D0=B0=D1=82=D1=8C=20?= =?UTF-8?q?=D0=B1=D0=B5=D1=81=D0=BA=D0=BE=D0=BD=D0=B5=D1=87=D0=BD=D1=83?= =?UTF-8?q?=D1=8E=20=D0=B8=D1=81=D1=82=D0=BE=D1=80=D0=B8=D1=8E=20=D1=81?= =?UTF-8?q?=D0=BE=20=D1=81=D0=BA=D0=BE=D1=80=D0=BE=D1=81=D1=82=D1=8C=D1=8E?= =?UTF-8?q?=20=D0=B4=D0=BE=D1=81=D1=82=D1=83=D0=BF=D0=B0=20=D0=9E(1).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kanban/service/HistoryManager.java | 2 + .../service/InMemoryHistoryManager.java | 79 +++++++-- src/ru/alexgur/kanban/service/Node.java | 50 ++++++ src/ru/alexgur/kanban/tests/Tests.java | 167 ++++++++++++++++-- 4 files changed, 274 insertions(+), 24 deletions(-) create mode 100644 src/ru/alexgur/kanban/service/Node.java diff --git a/src/ru/alexgur/kanban/service/HistoryManager.java b/src/ru/alexgur/kanban/service/HistoryManager.java index 58c8cf3..1d075ff 100644 --- a/src/ru/alexgur/kanban/service/HistoryManager.java +++ b/src/ru/alexgur/kanban/service/HistoryManager.java @@ -10,6 +10,8 @@ public interface HistoryManager { void clear(); + void remove(int id); + List getHistory(); } \ No newline at end of file diff --git a/src/ru/alexgur/kanban/service/InMemoryHistoryManager.java b/src/ru/alexgur/kanban/service/InMemoryHistoryManager.java index c350e8c..7a03fc8 100644 --- a/src/ru/alexgur/kanban/service/InMemoryHistoryManager.java +++ b/src/ru/alexgur/kanban/service/InMemoryHistoryManager.java @@ -1,21 +1,28 @@ package ru.alexgur.kanban.service; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; import java.util.List; import ru.alexgur.kanban.model.Task; public class InMemoryHistoryManager implements HistoryManager { - public static final int HISTORY_MAX_SIZE = 10; - - private ArrayList history = new ArrayList<>(); + private Node head; + private Node tail; + private HashMap history = new HashMap<>(); @Override public void clear() { clearImpl(); } + @Override + public void remove(int id) { + removeImpl(id); + } + @Override public void add(Task task) { addImpl(task); @@ -23,25 +30,75 @@ public void add(Task task) { @Override public List getHistory() { - return getHistoryImpl(); + List listTasks = new ArrayList<>(); + for (Node node : getTasks()) { + listTasks.add(node.getTask()); + } + return listTasks; + } + + private Node linkLast(Task task) { + final Node oldtail = tail; + final Node newNode = new Node(oldtail, task, null); + tail = newNode; + if (oldtail == null) { + head = newNode; + } else { + oldtail.setNext(newNode); + } + return newNode; + } + + private ArrayList getTasks() { + ArrayList nodes = new ArrayList<>(); + Node currentNode = head; + while (currentNode != null) { + nodes.add(currentNode); + currentNode = currentNode.getNext(); + } + Collections.reverse(nodes); + return nodes; } private void addImpl(Task task) { if (task != null) { - history.add(task); - if (history.size() > HISTORY_MAX_SIZE) { - history.remove(0); + if (history.containsKey(task.getId())) { + Node node = history.remove(task.getId()); + removeNode(node); } + Node node = linkLast(task); + history.put(task.getId(), node); + } + } + + private void removeNode(Node node) { + Node prev = node.getPrev(); + Node next = node.getNext(); + + if (prev != null && next != null) { + // Удаляетяся элемент в середине списка + next.setPrev(prev); + prev.setNext(next); + } else if (prev == null && next != null) { + // Удаляетяся первый элемент + head = next; + next.setPrev(null); + } else if (prev != null && next == null) { + // Удаляетяся последний элемент + tail = prev; + prev.setNext(null); } + + history.remove(node.getTask().getId()); } - private List getHistoryImpl() { - List res = history; - return List.copyOf(res); + private void removeImpl(int id) { + history.remove(id); } private void clearImpl() { + head = null; + tail = null; history.clear(); } - } diff --git a/src/ru/alexgur/kanban/service/Node.java b/src/ru/alexgur/kanban/service/Node.java new file mode 100644 index 0000000..f0f54d4 --- /dev/null +++ b/src/ru/alexgur/kanban/service/Node.java @@ -0,0 +1,50 @@ +package ru.alexgur.kanban.service; + +import ru.alexgur.kanban.model.Task; + +public class Node { + private Task task; + private Node next; + private Node prev; + + public Node(Node prev, Task task, Node next) { + this.task = task; + this.next = next; + this.prev = prev; + } + + @Override + public int hashCode() { + return task.hashCode(); + } + + @Override + public boolean equals(Object obj) { + Node other = (Node) obj; + return task.equals(other.task); + } + + public Task getTask() { + return task; + } + + public void setTask(Task task) { + this.task = task; + } + + public Node getNext() { + return next; + } + + public void setNext(Node next) { + this.next = next; + } + + public Node getPrev() { + return prev; + } + + public void setPrev(Node prev) { + this.prev = prev; + } +} diff --git a/src/ru/alexgur/kanban/tests/Tests.java b/src/ru/alexgur/kanban/tests/Tests.java index eb273b3..8afbf77 100644 --- a/src/ru/alexgur/kanban/tests/Tests.java +++ b/src/ru/alexgur/kanban/tests/Tests.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.ArrayList; import java.util.List; @@ -12,7 +13,6 @@ import ru.alexgur.kanban.service.Status; import ru.alexgur.kanban.service.TaskManager; import ru.alexgur.kanban.service.HistoryManager; -import ru.alexgur.kanban.service.InMemoryHistoryManager; import ru.alexgur.kanban.service.Managers; import org.junit.jupiter.api.Test; @@ -70,7 +70,7 @@ public void shouldNotBePossibleToAddEpicAsSubTask() { @Test public void shouldNotBePossibleToSetSubTaskAsItsOwnEpic() { SubTask subTask = new SubTask(); - + subTask.setEpicId(subTask.id); Assertions.assertNotEquals(subTask.id, subTask.getEpicId()); @@ -174,11 +174,11 @@ public void shouldSaveAndReturnOneRecordFromHistory() { Assertions.assertEquals(1, hist.size()); } - // проверка добавления в историю и чтения из неё ровно MAX элементов + // проверка добавления в историю и чтения из неё ровно 10 элементов @Test - public void shouldSaveAndReturnOneRecordsFromHistory() { + public void shouldSaveAndReturnTenRecordsFromHistory() { clearHistory(); - int max_hist_size = InMemoryHistoryManager.HISTORY_MAX_SIZE; + int max_hist_size = 10; for (int i = 0; i < max_hist_size; i++) { Task task = new Task(); @@ -190,11 +190,11 @@ public void shouldSaveAndReturnOneRecordsFromHistory() { Assertions.assertTrue(max_hist_size == hist.size()); } - // проверка добавления в историю и чтения из неё ровно MAX+1 элементов + // проверка добавления в историю и чтения из неё ровно 10+1 элементов @Test - public void shouldSaveAndReturnMaxPlusOneRecordFromHistory() { + public void shouldSaveAndReturnTenPlusOneRecordFromHistory() { clearHistory(); - int max_hist_size = InMemoryHistoryManager.HISTORY_MAX_SIZE; + int max_hist_size = 10; for (int i = 0; i < max_hist_size + 1; i++) { Task task = new Task(); @@ -203,7 +203,7 @@ public void shouldSaveAndReturnMaxPlusOneRecordFromHistory() { } List hist = tm.getHistoryManager().getHistory(); - Assertions.assertTrue(max_hist_size == hist.size()); + Assertions.assertTrue(max_hist_size + 1 == hist.size()); } @Test @@ -236,7 +236,7 @@ void addToHistory() { assertNotNull(history, "История не пустая."); assertEquals(1, history.size(), "История не пустая."); - } + } @Test void addNewTask() { @@ -251,9 +251,150 @@ void addNewTask() { assertNotNull(savedTask, "Задача не найдена."); assertEquals(task, savedTask, "Задачи не совпадают."); assertNotNull(tasks, "Задачи не возвращаются."); - assertEquals(taskSizeInit+1, tasks.size(), "Неверное количество задач."); - assertEquals(task, tasks.get(tasks.size()-1), "Задачи не совпадают."); - } + assertEquals(taskSizeInit + 1, tasks.size(), "Неверное количество задач."); + assertEquals(task, tasks.get(tasks.size() - 1), "Задачи не совпадают."); + } + + // Создайте две задачи, эпик с тремя подзадачами и эпик без подзадач. + // Запросите созданные задачи несколько раз в разном порядке. + // После каждого запроса выведите историю и убедитесь, что в ней нет повторов. + @Test + void shouldCreateTwoTasksAndOneEpicWithThreeSubtasksAndOneEptyEpic() { + clearHistory(); + List hist = tm.getHistoryManager().getHistory(); + + Task task1 = new Task(); + tm.addTask(task1); + hist = tm.getHistoryManager().getHistory(); + assertEquals(hist.size(), 0, "При создании задачи история просмотров не должна изменяться."); + + Task task2 = new Task(); + tm.addTask(task2); + hist = tm.getHistoryManager().getHistory(); + assertEquals(hist.size(), 0, "При создании задачи история просмотров не должна изменяться."); + + Epic epic1 = new Epic(); + tm.addEpic(epic1); + hist = tm.getHistoryManager().getHistory(); + assertEquals(hist.size(), 0, "При создании эпик задачи история просмотров не должна изменяться."); + + Epic epic2 = new Epic(); + tm.addEpic(epic2); + hist = tm.getHistoryManager().getHistory(); + assertEquals(hist.size(), 0, "При создании эпик задачи история просмотров не должна изменяться."); + + SubTask subTask1 = new SubTask(); + tm.addSubTask(subTask1); + hist = tm.getHistoryManager().getHistory(); + assertEquals(hist.size(), 0, "При создании подзадачи история просмотров не должна изменяться."); + + SubTask subTask2 = new SubTask(); + tm.addSubTask(subTask2); + hist = tm.getHistoryManager().getHistory(); + assertEquals(hist.size(), 0, "При создании подзадачи история просмотров не должна изменяться."); + + SubTask subTask3 = new SubTask(); + tm.addSubTask(subTask3); + hist = tm.getHistoryManager().getHistory(); + assertEquals(hist.size(), 0, "При создании подзадачи история просмотров не должна изменяться."); + + + task1.setName("Название1").setText("Описание1"); + hist = tm.getHistoryManager().getHistory(); + assertEquals(hist.size(), 0, "При изменении параметров задачи история просмотров не должна изменяться."); + + task2.setName("Название2").setText("Описание2"); + hist = tm.getHistoryManager().getHistory(); + assertEquals(hist.size(), 0, "При изменении параметров задачи история просмотров не должна изменяться."); + + epic1.setName("Название Epic 1").setText("Описание Epic 1"); + hist = tm.getHistoryManager().getHistory(); + assertEquals(hist.size(), 0, "При изменении параметров эпик задачи история просмотров не должна изменяться."); + + epic2.setName("Название Epic 2").setText("Описание Epic 2"); + hist = tm.getHistoryManager().getHistory(); + assertEquals(hist.size(), 0, "При изменении параметров эпик задачи история просмотров не должна изменяться."); + + subTask1.setName("Название SubTask 1").setText("Описание SubTask 1"); + hist = tm.getHistoryManager().getHistory(); + assertEquals(hist.size(), 0, "При изменении параметров подзадачи история просмотров не должна изменяться."); + + subTask2.setName("Название SubTask 2").setText("Описание SubTask 2"); + hist = tm.getHistoryManager().getHistory(); + assertEquals(hist.size(), 0, "При изменении параметров подзадачи история просмотров не должна изменяться."); + + subTask3.setName("Название SubTask 3").setText("Описание SubTask 3"); + hist = tm.getHistoryManager().getHistory(); + assertEquals(hist.size(), 0, "При изменении параметров подзадачи история просмотров не должна изменяться."); + + List sbtasks_ids = new ArrayList<>(); + sbtasks_ids.add(subTask1.id); + sbtasks_ids.add(subTask2.id); + sbtasks_ids.add(subTask3.id); + epic1.setSubTasksIds(sbtasks_ids); + subTask1.setEpicId(epic1.id); + subTask2.setEpicId(epic1.id); + subTask3.setEpicId(epic1.id); + hist = tm.getHistoryManager().getHistory(); + assertEquals(hist.size(), 0, "При добавлении подзадачи к эпику история просмотров не должна изменяться."); + + + tm.getTask(task1.id); + hist = tm.getHistoryManager().getHistory(); + assertTrue(hist.get(0).equals(task1)); + assertTrue(hist.size()==1); + + tm.getTask(task2.id); + hist = tm.getHistoryManager().getHistory(); + assertTrue(hist.get(0).equals(task2)); + assertTrue(hist.get(1).equals(task1)); + assertTrue(hist.size()==2); + + clearHistory(); + + tm.getTask(task2.id); + hist = tm.getHistoryManager().getHistory(); + assertTrue(hist.get(0).equals(task2)); + assertTrue(hist.size()==1); + + tm.getTask(task1.id); + hist = tm.getHistoryManager().getHistory(); + assertTrue(hist.get(0).equals(task1)); + assertTrue(hist.get(1).equals(task2)); + assertTrue(hist.size()==2); + + clearHistory(); + + tm.getTask(task1.id); + tm.getTask(task2.id); + tm.getTask(task1.id); + hist = tm.getHistoryManager().getHistory(); + assertTrue(hist.get(0).equals(task1)); + assertTrue(hist.get(1).equals(task2)); + assertTrue(hist.size()==2); + + + clearHistory(); + + tm.getTask(task1.id); + tm.getTask(task2.id); + tm.getTask(task1.id); + tm.getEpic(epic2.id); + tm.getSubTask(subTask2.id); + tm.getSubTask(subTask1.id); + tm.getEpic(epic1.id); + tm.getTask(task1.id); + tm.getEpic(epic2.id); + hist = tm.getHistoryManager().getHistory(); + + assertTrue(hist.get(0).equals(epic2)); + assertTrue(hist.get(1).equals(task1)); + assertTrue(hist.get(2).equals(epic1)); + assertTrue(hist.get(3).equals(subTask1)); + assertTrue(hist.get(4).equals(subTask2)); + assertTrue(hist.get(5).equals(task2)); + assertTrue(hist.size()==6); + } @Test public void shouldWorkAllTaskTogatherLikeInProduction() {