diff --git a/src/Main.java b/src/Main.java index ccfa2bb..854abdf 100644 --- a/src/Main.java +++ b/src/Main.java @@ -9,7 +9,7 @@ public class Main { // Метод для разделительной строки - private static void printDelimiter(){ + private static void printDelimiter() { System.out.println(); System.out.println("-".repeat(30)); } @@ -24,22 +24,21 @@ public static void main(String[] args) { manager.createTask(task1); manager.createTask(task2); - // Создание Эпика с двумя Подзадачами - Epic epic1 = new Epic("Эпик 1", "Эпик с 2 подзадачами"); + // Создание Эпика с тремя подзадачами + Epic epic1 = new Epic("Эпик 1", "Эпик с 3 подзадачами"); manager.createEpic(epic1); Subtask subtask1 = new Subtask("Подзадача 1", "Подзадача Эпика 1", Status.NEW, epic1.getId()); Subtask subtask2 = new Subtask("Подзадача 2", "Подзадача Эпика 1", Status.NEW, epic1.getId()); + Subtask subtask3 = new Subtask("Подзадача 3", "Подзадача Эпика 1", Status.NEW, epic1.getId()); manager.createSubtask(subtask1); manager.createSubtask(subtask2); + manager.createSubtask(subtask3); - // Создание Эпика с одной подзадачей - Epic epic2 = new Epic("Эпик 2", "Эпик с 1 подзадачей"); + // Создание Эпика без подзадач + Epic epic2 = new Epic("Эпик 2", "Эпик без подзадач"); manager.createEpic(epic2); - Subtask subtask3 = new Subtask("Подзадача 1", "Подзадача Эпика 2", Status.NEW, epic2.getId()); - manager.createSubtask(subtask3); - // Печать начального состояния списков Эпиков, Задач и Подзадач System.out.println("Задачи: " + manager.getTasks()); System.out.println(); @@ -50,15 +49,6 @@ public static void main(String[] args) { // Разделительная строка printDelimiter(); - // Изменение статуса Задачи 2 - task2.setStatus(Status.IN_PROGRESS); - manager.updateTask(task2); - System.out.println("Задача 2: в процессе"); - System.out.println("Статус задачи 2: " + manager.getTask(task2.getId()).getStatus()); - - // Разделительная строка - printDelimiter(); - // Изменение статуса Подзадач в Эпике 1 subtask1.setStatus(Status.DONE); subtask2.setStatus(Status.IN_PROGRESS); @@ -88,39 +78,37 @@ public static void main(String[] args) { // Разделительная строка printDelimiter(); - // Заполнение истории просмотра - System.out.println("Запрашиваем задачи, чтобы заполнить историю."); - - // много запросов, чтобы превысить лимит 10 + // Запрашивание задачи несколько раз в разном порядке + System.out.println("Запрашиваем задачи в разном порядке."); manager.getTask(task1.getId()); - manager.getTask(task2.getId()); manager.getEpic(epic1.getId()); manager.getSubtask(subtask1.getId()); + manager.getTask(task2.getId()); manager.getSubtask(subtask2.getId()); manager.getEpic(epic2.getId()); manager.getSubtask(subtask3.getId()); - // Повторные запросы (дубли) - manager.getTask(task1.getId()); - manager.getEpic(epic1.getId()); + // Повторные запросы = проверке, что дублей нет + manager.getTask(task1.getId()); // если task1 уже был = перемещение в конец + manager.getSubtask(subtask1.getId()); // если subtask1 уже был = перемещение в конец - // Еще запросы, чтобы вытеснить старые и проверить, выполняется ли лимит в 10 задач - manager.getTask(task2.getId()); - manager.getSubtask(subtask1.getId()); - - // Проверка истории - System.out.println("Проверка истории (10 элементов):"); + System.out.println("История (без повторов):"); printAllTasks(manager); - // Разделительная строка printDelimiter(); - // Удаление задачи и эпика - System.out.println("Удаляем задачу 1 и эпик 1"); + // Удаление задачи из истории + System.out.println("Удаляем задачу 1"); manager.deleteTask(task1.getId()); - manager.deleteEpic(epic1.getId()); + System.out.println("История после удаления задачи 1:"); + printAllTasks(manager); - System.out.println("Состояние после удаления:"); + printDelimiter(); + + // Удаление эпика с тремя подзадачами + System.out.println("Удаляем эпик 1 (с тремя подзадачами)"); + manager.deleteEpic(epic1.getId()); + System.out.println("История после удаления эпика 1 и его подзадач:"); printAllTasks(manager); } diff --git a/src/model/Epic.java b/src/model/Epic.java index e5c4dcd..00edfd5 100644 --- a/src/model/Epic.java +++ b/src/model/Epic.java @@ -10,7 +10,7 @@ public Epic(String name, String description) { } public ArrayList getSubtaskIds() { - return new ArrayList<>(subtaskIds);; + return new ArrayList<>(subtaskIds); } public void setSubtaskIds(ArrayList subtaskIds) { diff --git a/src/service/HistoryManager.java b/src/service/HistoryManager.java index 532225d..2508140 100644 --- a/src/service/HistoryManager.java +++ b/src/service/HistoryManager.java @@ -5,6 +5,8 @@ public interface HistoryManager { void add(Task task); - + + void remove(int id); + List getHistory(); } diff --git a/src/service/InMemoryHistoryManager.java b/src/service/InMemoryHistoryManager.java index 4a40100..1a4ad28 100644 --- a/src/service/InMemoryHistoryManager.java +++ b/src/service/InMemoryHistoryManager.java @@ -1,29 +1,125 @@ package service; +import model.Epic; +import model.Subtask; import model.Task; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public class InMemoryHistoryManager implements HistoryManager { - private static final int HISTORY_LIMIT = 10; - // Список для хранения истории просмотров задач - private final List history = new ArrayList<>(); + // Голова и хвост двусвязного списка + private Node head; + private Node tail; + + // В HashMap ключ = id задачи, значение = узел в списке + private final HashMap historyMap = new HashMap<>(); + + // Создание снимка задачи, чтобы история не зависела от внешних изменений + private Task makeSnapshot(Task task) { + if (task instanceof Subtask) { + Subtask original = (Subtask) task; + Subtask copy = new Subtask( + original.getName(), + original.getDescription(), + original.getStatus(), + original.getEpicId() + ); + copy.setId(original.getId()); + return copy; + } else if (task instanceof Epic) { + Epic original = (Epic) task; + Epic copy = new Epic(original.getName(), original.getDescription()); + copy.setId(original.getId()); + copy.setStatus(original.getStatus()); + copy.setSubtaskIds(original.getSubtaskIds()); + return copy; + } else { + Task copy = new Task(task.getName(), task.getDescription(), task.getStatus()); + copy.setId(task.getId()); + return copy; + } + } + + // Добавление задачи в конец двусвязного списка + private void linkLast(Task task) { + Node newNode = new Node(makeSnapshot(task)); + if (tail == null) { + // Если список пустой, то полностью новый узел - и голова, и хвост + head = newNode; + } else { + // Иначе подвешивание к хвосту + tail.setNext(newNode); + newNode.setPrev(tail); + } + tail = newNode; + + // Сохранение узла в индексе + historyMap.put(task.getId(), newNode); + } + + // Удаление конкретного узла из списка + private void removeNode(Node node) { + if (node == null) return; + + Node prevNode = node.getPrev(); + Node nextNode = node.getNext(); + + if (prevNode != null) { + prevNode.setNext(nextNode); // левый сосед смотрит на правого + } else { + head = nextNode; // удаление головы и новая голова - это следующий + } + + if (nextNode != null) { + nextNode.setPrev(prevNode); // правый сосед теперь смотрит на левого + } else { + tail = prevNode; // удаление хвоста и новый хвост - это предыдущий + } + + // Обнуление ссылок удалённого узла (помощь Garbage Collector) + node.setPrev(null); + node.setNext(null); + } + + // Сбор задач всех из двусвязного списка в ArrayList + private List getTasks() { + List result = new ArrayList<>(); + Node current = head; + while (current != null) { + result.add(current.getTask()); + current = current.getNext(); + } + return result; + } // Добавление в историю @Override public void add(Task task) { - history.add(task); - // Ограничение в 10 элементов - if (history.size() > HISTORY_LIMIT) { - history.remove(0); + if (task == null) return; + + // Если задача уже в истории = удаление старого просмотра + Node existingNode = historyMap.remove(task.getId()); + if (existingNode != null) { + removeNode(existingNode); } + + // Добавление копии в конец списка + linkLast(task); + } + + // Удаление задачи из истории по id + @Override + public void remove(int id) { + Node node = historyMap.remove(id); + removeNode(node); } // Возвращение списка истории @Override public List getHistory() { - return new ArrayList<>(history); + return getTasks(); } } diff --git a/src/service/InMemoryTaskManager.java b/src/service/InMemoryTaskManager.java index 584d125..1c4e95a 100644 --- a/src/service/InMemoryTaskManager.java +++ b/src/service/InMemoryTaskManager.java @@ -45,18 +45,37 @@ public ArrayList getSubtasks() { // Удаление всех задач для каждого из типов задач(Задача/Эпик/Подзадача) @Override public void clearTasks() { + // Удаление каждой задачи из истории перед очисткой хранилища + for (int id : tasks.keySet()) { + historyManager.remove(id); + } tasks.clear(); } @Override public void clearEpics() { + // Сначала удаление всех подзадач из истории + for (int id : subtasks.keySet()) { + historyManager.remove(id); + } + // Затем самих эпиков + for (int id : epics.keySet()) { + historyManager.remove(id); + } + epics.clear(); subtasks.clear(); } @Override public void clearSubtasks() { + // Удаление каждой подзадачи из истории + for (int id : subtasks.keySet()) { + historyManager.remove(id); + } + subtasks.clear(); + // Чистка Эпиков, если подзадач больше нет for (Epic epic : epics.values()) { epic.clearSubtaskIds(); @@ -68,28 +87,47 @@ public void clearSubtasks() { @Override public Task getTask(int id) { Task task = tasks.get(id); - if (task != null) { - historyManager.add(task); - } - return task; + if (task == null) return null; + + historyManager.add(task); + + Task copy = new Task(task.getName(), task.getDescription(), task.getStatus()); + copy.setId(task.getId()); + + return copy; } @Override public Epic getEpic(int id) { Epic epic = epics.get(id); - if (epic != null) { - historyManager.add(epic); - } - return epic; + if (epic == null) return null; + + historyManager.add(epic); + + Epic copy = new Epic(epic.getName(), epic.getDescription()); + copy.setId(epic.getId()); + copy.setStatus(epic.getStatus()); + copy.setSubtaskIds(epic.getSubtaskIds()); + + return copy; } @Override public Subtask getSubtask(int id) { Subtask subtask = subtasks.get(id); - if (subtask != null) { - historyManager.add(subtask); - } - return subtask; + if (subtask == null) return null; + + historyManager.add(subtask); + + Subtask copy = new Subtask( + subtask.getName(), + subtask.getDescription(), + subtask.getStatus(), + subtask.getEpicId() + ); + copy.setId(subtask.getId()); + + return copy; } // Возвращение списка истории @@ -197,6 +235,7 @@ public void updateSubtask(Subtask subtask) { @Override public void deleteTask(int id) { tasks.remove(id); + historyManager.remove(id); } @Override @@ -206,8 +245,10 @@ public void deleteEpic(int id) { // Удаление подзадач, связанных с этим Эпиком for (Integer subtaskId : epic.getSubtaskIds()) { subtasks.remove(subtaskId); + historyManager.remove(subtaskId); } } + historyManager.remove(id); } @Override @@ -221,18 +262,18 @@ public void deleteSubtask(int id) { updateEpicStatus(epic); } } + historyManager.remove(id); } // Получение списка всех Подзадач для определённого Эпика - @Override public ArrayList getEpicSubtasks(int epicId) { - ArrayList tasks = new ArrayList<>(); + ArrayList result = new ArrayList<>(); Epic epic = epics.get(epicId); if (epic != null) { for (int subtaskId : epic.getSubtaskIds()) { - tasks.add(subtasks.get(subtaskId)); + result.add(subtasks.get(subtaskId)); } } - return tasks; + return result; } } diff --git a/src/service/Managers.java b/src/service/Managers.java index 336dc6d..52faefe 100644 --- a/src/service/Managers.java +++ b/src/service/Managers.java @@ -6,7 +6,7 @@ private Managers() { } // Реализация TaskManager - public static TaskManager getDefault () { + public static TaskManager getDefault() { return new InMemoryTaskManager(); } diff --git a/src/service/Node.java b/src/service/Node.java new file mode 100644 index 0000000..df6bb51 --- /dev/null +++ b/src/service/Node.java @@ -0,0 +1,34 @@ +package service; + +import model.Task; + +// Двусвязный список с самой задачей и ссылками на соседей +public class Node { + private Task task; + private Node prev; + private Node next; + + public Node(Task task) { + this.task = task; + } + + public Task getTask() { + return task; + } + + public Node getPrev() { + return prev; + } + + public void setPrev(Node prev) { + this.prev = prev; + } + + public Node getNext() { + return next; + } + + public void setNext(Node next) { + this.next = next; + } +} \ No newline at end of file diff --git a/test/model/SubtaskTest.java b/test/model/SubtaskTest.java index da8fd5b..aedddc0 100644 --- a/test/model/SubtaskTest.java +++ b/test/model/SubtaskTest.java @@ -24,11 +24,11 @@ public void subtasksShouldBeEqualIfIdEquals(){ public void subtaskCannotBeEpic() { Subtask subtask = new Subtask("Subtask", "Description", Status.NEW, 3); - subtask.setId(3); + subtask.setId(5); + Assertions.assertEquals(5, subtask.getId(), "Корректный id должен установиться"); - Assertions.assertNotEquals(3, subtask.getId(), "Подзадача не должна позволять устанавливать ID, равный EpicID"); + subtask.setId(3); + Assertions.assertEquals(5, subtask.getId(), + "Подзадача не должна позволять устанавливать ID, равный EpicID"); } - - - } \ No newline at end of file diff --git a/test/service/InMemoryHistoryManagerTest.java b/test/service/InMemoryHistoryManagerTest.java index 4a45cd6..35de938 100644 --- a/test/service/InMemoryHistoryManagerTest.java +++ b/test/service/InMemoryHistoryManagerTest.java @@ -38,4 +38,143 @@ void add() { assertEquals(task.getStatus(), history.get(0).getStatus(), "Статус задачи в истории не совпадает"); assertEquals(task.getId(), history.get(0).getId(), "ID задачи в истории не совпадает"); } + + // При повторном добавлении задачи в историю дубликат не создастся + @Test + void addShouldNotCreateDuplicates() { + Task task = new Task("Task", "Description", Status.NEW); + task.setId(1); + + historyManager.add(task); + historyManager.add(task); // добавляем второй раз + historyManager.add(task); // и третий + + assertEquals(1, historyManager.getHistory().size(), "История не должна содержать дубликаты"); + } + + // История не должна ограничиваться 10 элементами + @Test + void historyShouldBeUnlimited() { + for (int i = 1; i <= 15; i++) { + Task task = new Task("Task " + i, "Description", Status.NEW); + task.setId(i); + historyManager.add(task); + } + + assertEquals(15, historyManager.getHistory().size(), "История должна хранить более 10 элементов"); + } + + // Удаление из начала истории + @Test + void removeShouldDeleteFromBeginning() { + Task task1 = new Task("Task1", "Desc", Status.NEW); + task1.setId(1); + Task task2 = new Task("Task2", "Desc", Status.NEW); + task2.setId(2); + Task task3 = new Task("Task3", "Desc", Status.NEW); + task3.setId(3); + + historyManager.add(task1); + historyManager.add(task2); + historyManager.add(task3); + + historyManager.remove(1); // удаление первой - головы + + List history = historyManager.getHistory(); + assertEquals(2, history.size(), "В истории должно остаться 2 задачи"); + assertEquals(2, history.get(0).getId(), "Первой должна быть task2"); + } + + // Удаление из середины истории + @Test + void removeShouldDeleteFromMiddle() { + Task task1 = new Task("Task1", "Desc", Status.NEW); + task1.setId(1); + Task task2 = new Task("Task2", "Desc", Status.NEW); + task2.setId(2); + Task task3 = new Task("Task3", "Desc", Status.NEW); + task3.setId(3); + + historyManager.add(task1); + historyManager.add(task2); + historyManager.add(task3); + + historyManager.remove(2); // удаление из середины + + List history = historyManager.getHistory(); + assertEquals(2, history.size(), "В истории должно остаться 2 задачи"); + assertEquals(1, history.get(0).getId(), "Первой должна быть task1"); + assertEquals(3, history.get(1).getId(), "Второй должна быть task3"); + } + + // Удаление из конца истории + @Test + void removeShouldDeleteFromEnd() { + Task task1 = new Task("Task1", "Desc", Status.NEW); + task1.setId(1); + Task task2 = new Task("Task2", "Desc", Status.NEW); + task2.setId(2); + Task task3 = new Task("Task3", "Desc", Status.NEW); + task3.setId(3); + + historyManager.add(task1); + historyManager.add(task2); + historyManager.add(task3); + + historyManager.remove(3); // удаление последней - хвоста + + List history = historyManager.getHistory(); + assertEquals(2, history.size(), "В истории должно остаться 2 задачи"); + assertEquals(2, history.get(1).getId(), "Последней должна быть task2"); + } + + // Повторный просмотр задачи должен переместить её в конец истории + @Test + void repeatedViewShouldMoveTaskToEnd() { + Task task1 = new Task("Task1", "Desc", Status.NEW); + task1.setId(1); + Task task2 = new Task("Task2", "Desc", Status.NEW); + task2.setId(2); + Task task3 = new Task("Task3", "Desc", Status.NEW); + task3.setId(3); + + historyManager.add(task1); + historyManager.add(task2); + historyManager.add(task3); + historyManager.add(task1); // task1 повторно — должна уйти в конец + + List history = historyManager.getHistory(); + + assertEquals(3, history.size(), "Дубликатов быть не должно"); + assertEquals(2, history.get(0).getId(), "Первой должна быть task2"); + assertEquals(3, history.get(1).getId(), "Второй должна быть task3"); + assertEquals(1, history.get(2).getId(), "Последней должна быть task1"); + } + + // Пустая история должна возвращать пустой список + @Test + void emptyHistoryShouldReturnEmptyList() { + List history = historyManager.getHistory(); + assertNotNull(history, "getHistory() не должен возвращать null"); + assertEquals(0, history.size(), "Пустая история должна содержать 0 элементов"); + } + + // Статус задачи в истории не должен меняться при изменении оригинала через сеттер + @Test + void historyShouldStoreSnapshotNotReference() { + Task task = new Task("Task", "Desc", Status.NEW); + task.setId(1); + + historyManager.add(task); + + // Меняем оригинал после добавления в историю + task.setName("Изменённое имя"); + task.setStatus(Status.DONE); + + Task inHistory = historyManager.getHistory().get(0); + assertEquals("Task", inHistory.getName(), + "История должна хранить снимок: имя не должно измениться"); + assertEquals(Status.NEW, inHistory.getStatus(), + "История должна хранить снимок: статус не должен измениться"); + } } \ No newline at end of file diff --git a/test/service/InMemoryTaskManagerTest.java b/test/service/InMemoryTaskManagerTest.java index 9c6beac..8a43bf2 100644 --- a/test/service/InMemoryTaskManagerTest.java +++ b/test/service/InMemoryTaskManagerTest.java @@ -80,7 +80,8 @@ void taskWithGeneratedIdShouldNotConflict() { taskManager.createTask(task); - assertNotEquals(999, task.getId(), "Менеджер должен игнорировать заданный вручную ID и генерировать уникальный"); + assertNotEquals(999, task.getId(), + "Менеджер должен игнорировать заданный вручную ID и генерировать уникальный"); Task savedTask = taskManager.getTask(task.getId()); assertNotNull(savedTask, "Задача должна быть найдена по сгенерированному ID"); @@ -105,7 +106,166 @@ void taskShouldBeUnchangedAfterAddingToManager() { // Проверяем assertEquals(expectedName, savedTask.getName(), "Имя задачи изменилось при сохранении"); - assertEquals(expectedDescription, savedTask.getDescription(), "Описание задачи изменилось при сохранении"); + assertEquals(expectedDescription, savedTask.getDescription(), + "Описание задачи изменилось при сохранении"); assertEquals(expectedStatus, savedTask.getStatus(), "Статус задачи изменился при сохранении"); } + + // Если удалена задача, то она должна исчезнуть из истории + @Test + void deletedTaskShouldBeRemovedFromHistory() { + Task task = new Task("Task", "Description", Status.NEW); + taskManager.createTask(task); + + taskManager.getTask(task.getId()); + assertEquals(1, taskManager.getHistory().size(), "Задача должна быть в истории"); + + taskManager.deleteTask(task.getId()); // удаляем + assertEquals(0, taskManager.getHistory().size(), + "Удалённая задача не должна оставаться в истории"); + } + + // При удалении эпика из истории удаляется и сам эпик, и все его подзадачи + @Test + void deletedEpicShouldBeRemovedFromHistoryWithSubtasks() { + Epic epic = new Epic("Epic", "Description"); + taskManager.createEpic(epic); + + Subtask subtask1 = new Subtask("Sub1", "Desc", Status.NEW, epic.getId()); + Subtask subtask2 = new Subtask("Sub2", "Desc", Status.NEW, epic.getId()); + taskManager.createSubtask(subtask1); + taskManager.createSubtask(subtask2); + + // Просматриваем всё — всё попадает в историю + taskManager.getEpic(epic.getId()); + taskManager.getSubtask(subtask1.getId()); + taskManager.getSubtask(subtask2.getId()); + assertEquals(3, taskManager.getHistory().size(), "В истории должно быть 3 элемента"); + + taskManager.deleteEpic(epic.getId()); // удаляем эпик + assertEquals(0, taskManager.getHistory().size(), + "После удаления эпика история должна быть пустой"); + } + + // Если удалена подзадача, то её id не должен оставаться внутри эпика + @Test + void deletedSubtaskShouldBeRemovedFromEpic() { + Epic epic = new Epic("Epic", "Description"); + taskManager.createEpic(epic); + + Subtask subtask = new Subtask("Sub", "Desc", Status.NEW, epic.getId()); + taskManager.createSubtask(subtask); + + int subtaskId = subtask.getId(); + taskManager.deleteSubtask(subtaskId); + + assertEquals(0, taskManager.getEpicSubtasks(epic.getId()).size(), + "После удаления подзадачи эпик не должен содержать её id"); + } + + // Изменение задачи через сеттер не должно влиять на данные внутри менеджера + @Test + void taskShouldNotChangeInManagerAfterSetterCall() { + Task task = new Task("Оригинальное имя", "Описание", Status.NEW); + taskManager.createTask(task); + + Task savedTask = taskManager.getTask(task.getId()); + savedTask.setName("Изменённое имя"); + + assertEquals("Оригинальное имя", + taskManager.getTask(task.getId()).getName(), + "Сеттер не должен менять данные задачи внутри менеджера"); + } + + // clearTasks() должен удалять задачи из истории + @Test + void clearTasksShouldRemoveTasksFromHistory() { + Task task1 = new Task("Task1", "Desc", Status.NEW); + Task task2 = new Task("Task2", "Desc", Status.NEW); + taskManager.createTask(task1); + taskManager.createTask(task2); + + taskManager.getTask(task1.getId()); + taskManager.getTask(task2.getId()); + assertEquals(2, taskManager.getHistory().size(), + "Перед очисткой в истории должно быть 2 задачи"); + + taskManager.clearTasks(); + + assertEquals(0, taskManager.getHistory().size(), + "После clearTasks история должна быть пустой"); + } + + // clearEpics() должен удалять эпики и их подзадачи из истории + @Test + void clearEpicsShouldRemoveEpicsAndSubtasksFromHistory() { + Epic epic = new Epic("Epic", "Desc"); + taskManager.createEpic(epic); + + Subtask subtask = new Subtask("Sub", "Desc", Status.NEW, epic.getId()); + taskManager.createSubtask(subtask); + + taskManager.getEpic(epic.getId()); + taskManager.getSubtask(subtask.getId()); + assertEquals(2, taskManager.getHistory().size(), + "Перед очисткой в истории должно быть 2 элемента"); + + taskManager.clearEpics(); + + assertEquals(0, taskManager.getHistory().size(), + "После clearEpics история должна быть пустой"); + } + + // Изменение подзадачи через сеттер не должно влиять на данные внутри менеджера + @Test + void subtaskShouldNotChangeInManagerAfterSetterCall() { + Epic epic = new Epic("Epic", "Desc"); + taskManager.createEpic(epic); + + Subtask subtask = new Subtask("Оригинальное имя", "Описание", Status.NEW, epic.getId()); + taskManager.createSubtask(subtask); + + Subtask savedSubtask = taskManager.getSubtask(subtask.getId()); + savedSubtask.setName("Изменённое имя"); + + assertEquals("Оригинальное имя", + taskManager.getSubtask(subtask.getId()).getName(), + "Сеттер не должен менять данные подзадачи внутри менеджера"); + } + + // clearSubtasks() должен удалять подзадачи из истории + @Test + void clearSubtasksShouldRemoveSubtasksFromHistory() { + Epic epic = new Epic("Epic", "Desc"); + taskManager.createEpic(epic); + + Subtask subtask = new Subtask("Sub", "Desc", Status.NEW, epic.getId()); + taskManager.createSubtask(subtask); + + taskManager.getSubtask(subtask.getId()); // добавление в историю + assertEquals(1, taskManager.getHistory().size(), + "Перед очисткой в истории должна быть 1 подзадача"); + + taskManager.clearSubtasks(); + + assertEquals(0, taskManager.getHistory().size(), + "После clearSubtasks история должна быть пустой"); + } + + // Проверка неизменности эпика по всем полям при добавлении в менеджер + @Test + void epicShouldBeUnchangedAfterAddingToManager() { + String expectedName = "Оригинальный эпик"; + String expectedDescription = "Описание эпика"; + + Epic epic = new Epic(expectedName, expectedDescription); + taskManager.createEpic(epic); + + Epic savedEpic = taskManager.getEpic(epic.getId()); + + assertEquals(expectedName, savedEpic.getName(), + "Имя эпика изменилось при сохранении"); + assertEquals(expectedDescription, savedEpic.getDescription(), + "Описание эпика изменилось при сохранении"); + } } \ No newline at end of file