diff --git a/Test/manager/InMemoryHistoryManagerTest.java b/Test/manager/InMemoryHistoryManagerTest.java deleted file mode 100644 index 6dfb7f4..0000000 --- a/Test/manager/InMemoryHistoryManagerTest.java +++ /dev/null @@ -1,86 +0,0 @@ -package manager; - -import model.Epic; -import model.Status; -import model.Subtask; -import model.Task; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - - -import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; - -class InMemoryHistoryManagerTest { - - private static TaskManager taskManager; - - @BeforeEach - public void beforeEach() { - taskManager = Managers.getDefault(); - } - - @Test - public void getHistoryShouldReturnListOf10Tasks() { - for (int i = 0; i < 20; i++) { - taskManager.addTask(new Task("Some name", "Some description")); - } - - List tasks = taskManager.getTasks(); - for (Task task : tasks) { - taskManager.getTaskByID(task.getId()); - } - - List list = taskManager.getHistory(); - assertEquals(10, list.size(), "Неверное количество элементов в истории "); - } - - @Test - public void getHistoryShouldReturnOldTaskAfterUpdate() { - Task washFloor = new Task("Помыть полы", "С новым средством"); - taskManager.addTask(washFloor); - taskManager.getTaskByID(washFloor.getId()); - taskManager.updateTask(new Task(washFloor.getId(), "Не забыть помыть полы", - "Можно и без средства", Status.IN_PROGRESS)); - List tasks = taskManager.getHistory(); - Task oldTask = tasks.getFirst(); - assertEquals(washFloor.getName(), oldTask.getName(), "В истории не сохранилась старая версия задачи"); - assertEquals(washFloor.getDescription(), oldTask.getDescription(), - "В истории не сохранилась старая версия задачи"); - - } - - @Test - public void getHistoryShouldReturnOldEpicAfterUpdate() { - Epic flatRenovation = new Epic(1, "Сделать ремонт", "Нужно успеть за отпуск"); - taskManager.addEpic(flatRenovation); - taskManager.getEpicByID(flatRenovation.getId()); - taskManager.updateEpic(new Epic(flatRenovation.getId(), "Новое имя", "новое описание" - )); - List epics = taskManager.getHistory(); - Epic oldEpic = (Epic) epics.getFirst(); - assertEquals(flatRenovation.getName(), oldEpic.getName(), - "В истории не сохранилась старая версия эпика"); - assertEquals(flatRenovation.getDescription(), oldEpic.getDescription(), - "В истории не сохранилась старая версия эпика"); - } - - @Test - public void getHistoryShouldReturnOldSubtaskAfterUpdate() { - Epic flatRenovation = new Epic(1, "Сделать ремонт", "Нужно успеть за отпуск"); - taskManager.addEpic(flatRenovation); - Subtask flatRenovationSubtask3 = new Subtask("Заказать книжный шкаф", "Из темного дерева", - flatRenovation.getId()); - taskManager.addSubtask(flatRenovationSubtask3); - taskManager.getSubtaskByID(flatRenovationSubtask3.getId()); - taskManager.updateSubtask(new Subtask(flatRenovationSubtask3.getId(), "Новое имя", - "новое описание", Status.IN_PROGRESS, flatRenovation.getId())); - List subtasks = taskManager.getHistory(); - Subtask oldSubtask = (Subtask) subtasks.getFirst(); - assertEquals(flatRenovationSubtask3.getName(), oldSubtask.getName(), - "В истории не сохранилась старая версия эпика"); - assertEquals(flatRenovationSubtask3.getDescription(), oldSubtask.getDescription(), - "В истории не сохранилась старая версия эпика"); - } -} \ No newline at end of file diff --git a/Test/manager/InMemoryTaskManagerTest.java b/Test/manager/InMemoryTaskManagerTest.java deleted file mode 100644 index 4cbfa5e..0000000 --- a/Test/manager/InMemoryTaskManagerTest.java +++ /dev/null @@ -1,159 +0,0 @@ -package manager; - -import model.Epic; -import model.Status; -import model.Subtask; -import model.Task; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - - -import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; - -class InMemoryTaskManagerTest { - - private static TaskManager taskManager; - - @BeforeEach - public void beforeEach() { - taskManager = Managers.getDefault(); - } - - @Test - void addNewTask() { - //проверяем, что InMemoryTaskManager добавляет задачи и может найти их по id; - final Task task = taskManager.addTask(new Task("Test addNewTask", "Test addNewTask description")); - final Task savedTask = taskManager.getTaskByID(task.getId()); - assertNotNull(savedTask, "Задача не найдена."); - assertEquals(task, savedTask, "Задачи не совпадают."); - - final List tasks = taskManager.getTasks(); - assertNotNull(tasks, "Задачи не возвращаются."); - assertEquals(1, tasks.size(), "Неверное количество задач."); - assertEquals(task, tasks.getFirst(), "Задачи не совпадают."); - } - - @Test - void addNewEpicAndSubtasks() { - //проверяем, что InMemoryTaskManager добавляет эпики и подзадачи и может найти их по id; - final Epic flatRenovation = taskManager.addEpic(new Epic(1, "Сделать ремонт", "Нужно успеть за отпуск")); - final Subtask flatRenovationSubtask1 = taskManager.addSubtask(new Subtask("Поклеить обои", - "Обязательно светлые!", flatRenovation.getId())); - final Subtask flatRenovationSubtask2 = taskManager.addSubtask(new Subtask("Установить новую технику", - "Старую продать на Авито", flatRenovation.getId())); - final Subtask flatRenovationSubtask3 = taskManager.addSubtask(new Subtask("Заказать книжный шкаф", "Из темного дерева", - flatRenovation.getId())); - final Epic savedEpic = taskManager.getEpicByID(flatRenovation.getId()); - final Subtask savedSubtask1 = taskManager.getSubtaskByID(flatRenovationSubtask1.getId()); - final Subtask savedSubtask2 = taskManager.getSubtaskByID(flatRenovationSubtask2.getId()); - final Subtask savedSubtask3 = taskManager.getSubtaskByID(flatRenovationSubtask3.getId()); - assertNotNull(savedEpic, "Эпик не найден."); - assertNotNull(savedSubtask2, "Подзадача не найдена."); - assertEquals(flatRenovation, savedEpic, "Эпики не совпадают."); - assertEquals(flatRenovationSubtask1, savedSubtask1, "Подзадачи не совпадают."); - assertEquals(flatRenovationSubtask3, savedSubtask3, "Подзадачи не совпадают."); - - final List epics = taskManager.getEpics(); - assertNotNull(epics, "Эпики не возвращаются."); - assertEquals(1, epics.size(), "Неверное количество эпиков."); - assertEquals(flatRenovation, epics.getFirst(), "Эпики не совпадают."); - - final List subtasks = taskManager.getSubtasks(); - assertNotNull(subtasks, "Подзадачи не возвращаются."); - assertEquals(3, subtasks.size(), "Неверное количество подзадач."); - assertEquals(savedSubtask1, subtasks.getFirst(), "Подзадачи не совпадают."); - } - - @Test - public void updateTaskShouldReturnTaskWithTheSameId() { - final Task expected = new Task("имя", "описание"); - taskManager.addTask(expected); - final Task updatedTask = new Task(expected.getId(), "новое имя", "новое описание", Status.DONE); - final Task actual = taskManager.updateTask(updatedTask); - assertEquals(expected, actual, "Вернулась задачи с другим id"); - } - - - @Test - public void updateSubtaskShouldReturnSubtaskWithTheSameId() { - final Epic epic = new Epic(1, "Сделать ремонт", "Нужно успеть за отпуск"); - taskManager.addEpic(epic); - final Subtask expected = new Subtask("имя", "описание", epic.getId()); - taskManager.addSubtask(expected); - final Subtask updatedSubtask = new Subtask(expected.getId(), "новое имя", "новое описание", - Status.DONE, epic.getId()); - final Subtask actual = taskManager.updateSubtask(updatedSubtask); - assertEquals(expected, actual, "Вернулась подзадача с другим id"); - } - - @Test - public void deleteTasksShouldReturnEmptyList() { - taskManager.addTask(new Task("Купить книги", "Список в заметках")); - taskManager.addTask(new Task("Помыть полы", "С новым средством")); - taskManager.deleteTasks(); - List tasks = taskManager.getTasks(); - assertTrue(tasks.isEmpty(), "После удаления задач список должен быть пуст."); - } - - @Test - public void deleteEpicsShouldReturnEmptyList() { - taskManager.addEpic(new Epic(1, "Сделать ремонт", "Нужно успеть за отпуск")); - taskManager.deleteEpics(); - List epics = taskManager.getEpics(); - assertTrue(epics.isEmpty(), "После удаления эпиков список должен быть пуст."); - } - - @Test - public void deleteSubtasksShouldReturnEmptyList() { - Epic flatRenovation = new Epic(1, "Сделать ремонт", "Нужно успеть за отпуск"); - taskManager.addEpic(flatRenovation); - taskManager.addSubtask(new Subtask("Поклеить обои", "Обязательно светлые!", - flatRenovation.getId())); - taskManager.addSubtask(new Subtask("Установить новую технику", "Старую продать на Авито", - flatRenovation.getId())); - taskManager.addSubtask(new Subtask("Заказать книжный шкаф", "Из темного дерева", - flatRenovation.getId())); - - taskManager.deleteSubtasks(); - List subtasks = taskManager.getSubtasks(); - assertTrue(subtasks.isEmpty(), "После удаления подзадач список должен быть пуст."); - } - - @Test - public void tasksWithEqualIdShouldBeEqual() { - Task task1 = new Task(10, "Забрать заказ", "На Ozon", Status.NEW); - Task task2 = new Task(10, "Забрать заказ", "На Wildberries", Status.DONE); - assertEquals(task1, task2, "Ошибка! Экземпляры класса Task должны быть равны друг другу, если равен их id;"); - } - - @Test - public void EpicsWithEqualIdShouldBeEqual() { - Epic epic1 = new Epic(10, "Сделать ремонт", "Уложиться в 2 миллиона"); - Epic epic2 = new Epic(10, "Подготовиться к собеседованию", "1 июля в 11:00"); - assertEquals(epic1, epic2, - "Ошибка! Наследники класса Task должны быть равны друг другу, если равен их id;"); - } - - @Test - public void SubtasksWithEqualEpicIDShouldBeEqual() { - Subtask subtask1 = new Subtask(10, "Забрать заказ", "На Ozon", Status.NEW, 5); - Subtask subtask2 = new Subtask(10, "Забрать заказ", "На Wildberries", Status.DONE, 5); - assertEquals(subtask1, subtask2, "Ошибка! Наследники класса Task должны быть равны друг другу, если равен их epicID;"); - } - - - @Test - void TaskCreatedAndTaskAddedShouldHaveSameVariables() { - Task expected = new Task(1, "Помыть полы", "С новым средством", Status.DONE); - taskManager.addTask(expected); - List list = taskManager.getTasks(); - Task actual = list.getFirst(); - assertEquals(expected.getId(), actual.getId()); - assertEquals(expected.getName(), actual.getName()); - assertEquals(expected.getDescription(), actual.getDescription()); - assertEquals(expected.getStatus(), actual.getStatus()); - } - -} \ No newline at end of file diff --git a/Test/model/SubtaskTest.java b/Test/model/SubtaskTest.java deleted file mode 100644 index 626c7c1..0000000 --- a/Test/model/SubtaskTest.java +++ /dev/null @@ -1,16 +0,0 @@ -package model; - -import org.junit.jupiter.api.Test; - - -import static org.junit.jupiter.api.Assertions.*; - -class SubtaskTest { - - @Test - public void SubtasksWithEqualEpicIDShouldBeEqual() { - Subtask subtask1 = new Subtask(10, "Забрать заказ", "На Ozon", Status.NEW, 5); - Subtask subtask2 = new Subtask(10, "Забрать заказ", "На Wildberries", Status.DONE, 5); - assertEquals(subtask1, subtask2, "Ошибка! Наследники класса Task должны быть равны друг другу, если равен их epicID;"); - } -} \ No newline at end of file diff --git a/java-kanban.iml b/java-kanban.iml index 55a0bff..9d56d29 100644 --- a/java-kanban.iml +++ b/java-kanban.iml @@ -4,7 +4,7 @@ - + diff --git a/module-info.java b/module-info.java new file mode 100644 index 0000000..e69de29 diff --git a/src/Main.java b/src/Main.java index 23497af..4a1dd43 100644 --- a/src/Main.java +++ b/src/Main.java @@ -1,13 +1,17 @@ import manager.Managers; import manager.TaskManager; import model.Epic; -import model.Status; import model.Subtask; import model.Task; +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + public class Main { private static final TaskManager taskManager = Managers.getDefault(); + private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); public static void main(String[] args) { addTasks(); @@ -16,63 +20,78 @@ public static void main(String[] args) { } private static void addTasks() { - Task packBoxes = new Task("Упаковать вещи", "В коробки и мешки"); + LocalDateTime now = LocalDateTime.now(); + + Task packBoxes = new Task("Упаковать вещи", "В коробки и мешки", Duration.ofMinutes(30), now); taskManager.addTask(packBoxes); - Task packBoxesToUpdate = new Task(packBoxes.getId(), "Упаковать вещи быстро", "В коробки и мешки", - Status.IN_PROGRESS); - taskManager.updateTask(packBoxesToUpdate); - taskManager.addTask(new Task("Придумать список дел после перезда", "Список в заметках")); + Task createToDoList = new Task("Придумать список дел после перезда", "Список в заметках", Duration.ofMinutes(15), now.plusMinutes(50)); + taskManager.addTask(createToDoList); Epic moving = new Epic(10, "Переезд", "Нужно успеть до конца месяца"); taskManager.addEpic(moving); - Subtask packKitchen = new Subtask("Упаковать кухню", "В отдельные коробки", - moving.getId()); - Subtask packBedroom = new Subtask("Упаковать спальню", "В большие коробки", - moving.getId()); + + Subtask packKitchen = new Subtask("Упаковать кухню", "В отдельные коробки", moving.getId(), Duration.ofMinutes(30), now.plusMinutes(65)); + Subtask packBedroom = new Subtask("Упаковать спальню", "В большие коробки", moving.getId(), Duration.ofMinutes(30), now.plusMinutes(95)); + taskManager.addSubtask(packKitchen); taskManager.addSubtask(packBedroom); - packBedroom.setStatus(Status.DONE); - taskManager.updateSubtask(packBedroom); } private static void printAllTasks() { System.out.println("Задачи:"); - for (Task task : taskManager.getTasks()) { - System.out.println(task); - } - System.out.println("Эпики:"); - for (Epic epic : taskManager.getEpics()) { - System.out.println(epic); + taskManager.getTasks().stream() + .map(Main::formatTask) + .forEach(System.out::println); - for (Task task : taskManager.getEpicSubtasks(epic)) { - System.out.println("--> " + task); - } - } + System.out.println("Эпики:"); + taskManager.getEpics().forEach(epic -> { + System.out.println(formatEpic(epic)); + taskManager.getEpicSubtasks(epic).stream() + .map(Main::formatSubtask) + .forEach(subtask -> System.out.println("--> " + subtask)); + }); System.out.println("Подзадачи:"); - for (Task subtask : taskManager.getSubtasks()) { - System.out.println(subtask); - } + taskManager.getSubtasks().stream() + .map(Main::formatSubtask) + .forEach(System.out::println); + } + + private static String formatTask(Task task) { + String startTime = task.getStartTime() != null ? task.getStartTime().format(formatter) : "не задано"; + return String.format("Task{id=%d, name='%s', description='%s', status=%s, duration=%s, startTime=%s}", + task.getId(), task.getName(), task.getDescription(), task.getStatus(), task.getDuration(), startTime); + } + + private static String formatSubtask(Subtask subtask) { + String startTime = subtask.getStartTime() != null ? subtask.getStartTime().format(formatter) : "не задано"; + return String.format("Subtask{name='%s', description='%s', id=%d, epicID=%d, status=%s, duration=%s, startTime=%s}", + subtask.getName(), subtask.getDescription(), subtask.getId(), subtask.getEpicID(), subtask.getStatus(), subtask.getDuration(), startTime); + } + + private static String formatEpic(Epic epic) { + String startTime = epic.getStartTime() != null ? epic.getStartTime().format(formatter) : "не задано"; + return String.format("Epic{name='%s', description='%s', id=%d, subtaskList.size=%d, status=%s, duration=%s, startTime=%s}", + epic.getName(), epic.getDescription(), epic.getId(), epic.getSubtaskList().size(), epic.getStatus(), epic.getDuration(), startTime); } private static void printViewHistory() { taskManager.getTaskByID(1); taskManager.getTaskByID(2); - taskManager.getEpicByID(3); + taskManager.getEpicByID(10); taskManager.getTaskByID(1); taskManager.getSubtaskByID(4); taskManager.getSubtaskByID(5); - taskManager.getSubtaskByID(6); - taskManager.getEpicByID(3); + taskManager.getEpicByID(10); taskManager.getSubtaskByID(4); taskManager.getTaskByID(2); - taskManager.getSubtaskByID(6); + taskManager.getSubtaskByID(5); System.out.println(); System.out.println("История просмотров:"); for (Task task : taskManager.getHistory()) { - System.out.println(task); + System.out.println(formatTask(task)); } } } \ No newline at end of file diff --git a/src/exceptions/ManagerSaveException.java b/src/exceptions/ManagerSaveException.java new file mode 100644 index 0000000..e43db7e --- /dev/null +++ b/src/exceptions/ManagerSaveException.java @@ -0,0 +1,7 @@ +package exceptions; + +public class ManagerSaveException extends RuntimeException { + public ManagerSaveException(String message, Throwable cause) { + super(message, cause); + } +} \ No newline at end of file diff --git a/src/manager/FileBackedTaskManager.java b/src/manager/FileBackedTaskManager.java new file mode 100644 index 0000000..ccb3301 --- /dev/null +++ b/src/manager/FileBackedTaskManager.java @@ -0,0 +1,181 @@ +package manager; + +import exceptions.ManagerSaveException; +import model.Epic; + +import model.Status; +import model.Subtask; +import model.Task; +import tasktype.TaskType; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.List; + +public class FileBackedTaskManager extends InMemoryTaskManager { + private final File file; + + public FileBackedTaskManager(File file) { + this.file = file; + } + + @Override + public Task addTask(Task task) { + Task addedTask = super.addTask(task); + save(); + return addedTask; + } + + @Override + public Epic addEpic(Epic epic) { + Epic addedEpic = super.addEpic(epic); + save(); + return addedEpic; + } + + @Override + public Subtask addSubtask(Subtask subtask) { + Subtask addedSubtask = super.addSubtask(subtask); + save(); + return addedSubtask; + } + + @Override + public Task updateTask(Task updatedTask) { + Task existingTask = super.updateTask(updatedTask); + save(); + return existingTask; + } + + @Override + public Epic updateEpic(Epic updatedEpic) { + Epic existingEpic = super.updateEpic(updatedEpic); + save(); + return existingEpic; + } + + @Override + public Subtask updateSubtask(Subtask updatedSubtask) { + Subtask existingSubtask = super.updateSubtask(updatedSubtask); + save(); + return existingSubtask; + } + + @Override + public void deleteTaskByID(int id) { + super.deleteTaskByID(id); + save(); + } + + @Override + public void deleteEpicByID(int id) { + super.deleteEpicByID(id); + save(); + } + + @Override + public void deleteSubtaskByID(int id) { + super.deleteSubtaskByID(id); + save(); + } + + @Override + public void deleteTasks() { + super.deleteTasks(); + save(); + } + + @Override + public void deleteEpics() { + super.deleteEpics(); + save(); + } + + @Override + public void deleteSubtasks() { + super.deleteSubtasks(); + save(); + } + + public void save() { + try (PrintWriter writer = new PrintWriter(file)) { + writer.println("id,type,name,status,description,epic,duration,startTime"); + for (Task task : getTasks()) { + writer.println(toString(task)); + } + for (Epic epic : getEpics()) { + writer.println(toString(epic)); + } + for (Subtask subtask : getSubtasks()) { + writer.println(toString(subtask)); + } + } catch (IOException e) { + throw new ManagerSaveException("Failed to save tasks to file", e); + } + } + + private String toString(Task task) { + StringBuilder sb = new StringBuilder(); + sb.append(task.getId()).append(",").append(task.getType()).append(",").append(task.getName()).append(",").append(task.getStatus()).append(",").append(task.getDescription()).append(","); + + if (task instanceof Subtask) { + sb.append(((Subtask) task).getEpicID()).append(","); + } else { + sb.append(","); + } + + sb.append(task.getDuration() != null ? task.getDuration().toMinutes() : 0).append(",").append(task.getStartTime() != null ? task.getStartTime() : ""); + + return sb.toString(); + } + + public static FileBackedTaskManager loadFromFile(File file) { + FileBackedTaskManager manager = new FileBackedTaskManager(file); + try { + List lines = Files.readAllLines(file.toPath()); + if (lines.size() > 1) { + for (String line : lines.subList(1, lines.size())) { + Task task = fromString(line); + if (task instanceof Epic) { + manager.addEpic((Epic) task); + } else if (task instanceof Subtask) { + manager.addSubtask((Subtask) task); + } else { + manager.addTask(task); + } + } + } + } catch (IOException e) { + throw new ManagerSaveException("Failed to load tasks from file", e); + } + return manager; + } + + private static Task fromString(String value) { + String[] parts = value.split(","); + int id = Integer.parseInt(parts[0]); + String type = parts[1]; + String name = parts[2]; + Status status = Status.valueOf(parts[3]); + String description = parts[4]; + + TaskType taskType = TaskType.valueOf(type); + Duration duration = Duration.ofMinutes(Long.parseLong(parts[6])); + LocalDateTime startTime = parts.length > 7 && !parts[7].isEmpty() ? LocalDateTime.parse(parts[7]) : null; + + switch (taskType) { + case SUBTASK: + int epicID = Integer.parseInt(parts[5]); + return new Subtask(id, name, description, status, duration, startTime, epicID); + case EPIC: + return new Epic(id, name, description, status, duration, startTime); + case TASK: + default: + return new Task(id, name, description, status, duration, startTime); + } + } +} \ No newline at end of file diff --git a/src/manager/HistoryManager.java b/src/manager/HistoryManager.java index b2bcde7..d06a752 100644 --- a/src/manager/HistoryManager.java +++ b/src/manager/HistoryManager.java @@ -5,6 +5,11 @@ import java.util.List; public interface HistoryManager { + void add(Task task); + + void remove(int id); + List getHistory(); + } \ No newline at end of file diff --git a/src/manager/InMemoryHistoryManager.java b/src/manager/InMemoryHistoryManager.java index b9908b3..168ec0d 100644 --- a/src/manager/InMemoryHistoryManager.java +++ b/src/manager/InMemoryHistoryManager.java @@ -4,20 +4,122 @@ import java.util.*; - public class InMemoryHistoryManager implements HistoryManager { - private final List history = new ArrayList<>(); + private static class CustomLinkedList { + private final Map table = new HashMap<>(); + private Node head; + private Node tail; + + private static class Node { + private Task task; + private Node prev; + private Node next; + + public Task getTask() { + return task; + } + + public void setTask(Task task) { + this.task = 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; + } + } + + private void linkLast(Task task) { + Node element = new Node(); + element.setTask(task); + + if (table.containsKey(task.getId())) { + removeNode(table.get(task.getId())); + } + + if (head == null) { + tail = element; + head = element; + element.setNext(null); + element.setPrev(null); + } else { + element.setPrev(tail); + element.setNext(null); + tail.setNext(element); + tail = element; + } + + table.put(task.getId(), element); + } + + private List getTasks() { + List result = new ArrayList<>(); + Node element = head; + while (element != null) { + result.add(element.getTask()); + element = element.getNext(); + } + return result; + } + + private void removeNode(Node node) { + if (node != null) { + table.remove(node.getTask().getId()); + Node prev = node.getPrev(); + Node next = node.getNext(); + + if (head == node) { + head = node.getNext(); + } + if (tail == node) { + tail = node.getPrev(); + } + + if (prev != null) { + prev.setNext(next); + } + + if (next != null) { + next.setPrev(prev); + } + } + } + + private Node getNode(int id) { + return table.get(id); + } + } + + private final CustomLinkedList list = new CustomLinkedList(); + @Override public void add(Task task) { - if (history.size() >= 10) { - history.remove(0); - } - history.add(task); + list.linkLast(task); + } + + + @Override + public void remove(int id) { + list.removeNode(list.getNode(id)); } + @Override public List getHistory() { - return List.copyOf(history); + return list.getTasks(); } -} \ No newline at end of file +} + + diff --git a/src/manager/InMemoryTaskManager.java b/src/manager/InMemoryTaskManager.java index aa804bd..665bad6 100644 --- a/src/manager/InMemoryTaskManager.java +++ b/src/manager/InMemoryTaskManager.java @@ -1,31 +1,38 @@ package manager; - import model.Epic; import model.Status; import model.Subtask; import model.Task; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.time.ZoneOffset; +import java.util.*; public class InMemoryTaskManager implements TaskManager { private final Map tasks = new HashMap<>(); private final Map epics = new HashMap<>(); private final Map subtasks = new HashMap<>(); private final HistoryManager historyManager; + private final Set prioritizedTasks = new TreeSet<>(Comparator.comparing(Task::getStartTime, Comparator.nullsLast(Comparator.naturalOrder()))); private int nextID = 1; public InMemoryTaskManager() { this.historyManager = Managers.getDefaultHistory(); } + private int getNextID() { + return nextID++; + } + @Override public Task addTask(Task task) { + validateTask(task); + if (isOverlapping(task)) { + throw new IllegalArgumentException("Task overlaps with existing task"); + } task.setId(getNextID()); tasks.put(task.getId(), task); + prioritizedTasks.add(task); return task; } @@ -38,22 +45,41 @@ public Epic addEpic(Epic epic) { @Override public Subtask addSubtask(Subtask subtask) { - subtask.setId(getNextID()); Epic epic = epics.get(subtask.getEpicID()); + if (epic == null) { + throw new IllegalArgumentException("Epic with ID " + subtask.getEpicID() + " does not exist."); + } + validateTask(subtask); + + subtask.setId(getNextID()); + + while (isOverlapping(subtask)) { + subtask.setStartTime(subtask.getStartTime().plusMinutes(10)); + } + epic.addSubtask(subtask); subtasks.put(subtask.getId(), subtask); + prioritizedTasks.add(subtask); updateEpicStatus(epic); return subtask; } @Override - public Task updateTask(Task task) { - Integer taskID = task.getId(); - if (taskID == null || !tasks.containsKey(taskID)) { - return null; + public Task updateTask(Task updatedTask) { + validateTask(updatedTask); + Task existingTask = getTaskByID(updatedTask.getId()); + if (existingTask != null) { + tasks.remove(existingTask.getId()); + prioritizedTasks.remove(existingTask); + if (isOverlapping(updatedTask)) { + tasks.put(existingTask.getId(), existingTask); + prioritizedTasks.add(existingTask); + throw new IllegalArgumentException("Task overlaps with existing task"); + } + tasks.put(updatedTask.getId(), updatedTask); + prioritizedTasks.add(updatedTask); } - tasks.replace(taskID, task); - return task; + return existingTask; } @Override @@ -62,23 +88,7 @@ public Epic updateEpic(Epic epic) { if (epicID == null || !epics.containsKey(epicID)) { return null; } - // если у эпика были подзадачи, удаляем их из мапы с подзадачами - Epic oldEpic = epics.get(epicID); - ArrayList oldEpicSubtaskList = oldEpic.getSubtaskList(); - if (!oldEpicSubtaskList.isEmpty()) { - for (Subtask subtask : oldEpicSubtaskList) { - subtasks.remove(subtask.getId()); - } - } - epics.replace(epicID, epic); - // если у обновленного эпика есть подзадачи, добавляем их в мапу подзадач - ArrayList newEpicSubtaskList = epic.getSubtaskList(); - if (!newEpicSubtaskList.isEmpty()) { - for (Subtask subtask : newEpicSubtaskList) { - subtasks.put(subtask.getId(), subtask); - } - } - // обновляем статус эпика + epics.put(epicID, epic); updateEpicStatus(epic); return epic; } @@ -90,14 +100,23 @@ public Subtask updateSubtask(Subtask subtask) { return null; } int epicID = subtask.getEpicID(); - Subtask oldSubtask = subtasks.get(subtaskID); - subtasks.replace(subtaskID, subtask); - // обновляем подзадачу в списке подзадач эпика и проверяем статус эпика Epic epic = epics.get(epicID); - ArrayList subtaskList = epic.getSubtaskList(); - subtaskList.remove(oldSubtask); - subtaskList.add(subtask); - epic.setSubtaskList(subtaskList); + Subtask oldSubtask = subtasks.get(subtaskID); + + epic.getSubtaskList().remove(oldSubtask); + subtasks.remove(subtaskID); + prioritizedTasks.remove(oldSubtask); + + if (isOverlapping(subtask)) { + epic.getSubtaskList().add(oldSubtask); + subtasks.put(subtaskID, oldSubtask); + prioritizedTasks.add(oldSubtask); + throw new IllegalArgumentException("Subtask overlaps with existing task"); + } + + subtasks.put(subtaskID, subtask); + prioritizedTasks.add(subtask); + epic.addSubtask(subtask); updateEpicStatus(epic); return subtask; } @@ -151,49 +170,76 @@ public ArrayList getEpicSubtasks(Epic epic) { @Override public void deleteTasks() { + for (Task task : tasks.values()) { + historyManager.remove(task.getId()); + prioritizedTasks.remove(task); + } tasks.clear(); } @Override public void deleteEpics() { + for (Epic epic : epics.values()) { + for (Subtask subtask : epic.getSubtaskList()) { + subtasks.remove(subtask.getId()); + prioritizedTasks.remove(subtask); + historyManager.remove(subtask.getId()); + } + } epics.clear(); - subtasks.clear(); } @Override public void deleteSubtasks() { - subtasks.clear(); - for (Epic epic : epics.values()) { - epic.clearSubtasks(); - epic.setStatus(Status.NEW); + for (Subtask subtask : new ArrayList<>(subtasks.values())) { + int epicID = subtask.getEpicID(); + subtasks.remove(subtask.getId()); + prioritizedTasks.remove(subtask); + historyManager.remove(subtask.getId()); + Epic epic = epics.get(epicID); + if (epic != null) { + epic.getSubtaskList().remove(subtask); + updateEpicStatus(epic); + } } } @Override public void deleteTaskByID(int id) { - tasks.remove(id); + Task task = tasks.remove(id); + if (task != null) { + prioritizedTasks.remove(task); + historyManager.remove(id); + } } @Override public void deleteEpicByID(int id) { - ArrayList epicSubtasks = epics.get(id).getSubtaskList(); - epics.remove(id); - for (Subtask subtask : epicSubtasks) { - subtasks.remove(subtask.getId()); + Epic epic = epics.get(id); + if (epic != null) { + for (Subtask subtask : epic.getSubtaskList()) { + subtasks.remove(subtask.getId()); + prioritizedTasks.remove(subtask); + historyManager.remove(subtask.getId()); + } + epics.remove(id); } } @Override public void deleteSubtaskByID(int id) { Subtask subtask = subtasks.get(id); - int epicID = subtask.getEpicID(); - subtasks.remove(id); - // обновляем список подзадач и статус эпика - Epic epic = epics.get(epicID); - ArrayList subtaskList = epic.getSubtaskList(); - subtaskList.remove(subtask); - epic.setSubtaskList(subtaskList); - updateEpicStatus(epic); + if (subtask != null) { + int epicID = subtask.getEpicID(); + subtasks.remove(id); + prioritizedTasks.remove(subtask); + historyManager.remove(id); + Epic epic = epics.get(epicID); + if (epic != null) { + epic.getSubtaskList().remove(subtask); + updateEpicStatus(epic); + } + } } @Override @@ -201,8 +247,35 @@ public List getHistory() { return historyManager.getHistory(); } - private int getNextID() { - return nextID++; + @Override + public List getPrioritizedTasks() { + return new ArrayList<>(prioritizedTasks); + } + + private boolean isOverlapping(Task newTask) { + for (Task existingTask : tasks.values()) { + if (existingTask.getId() != newTask.getId() && isOverlapping(existingTask, newTask)) { + return true; + } + } + for (Subtask existingSubtask : subtasks.values()) { + if (existingSubtask.getId() != newTask.getId() && isOverlapping(existingSubtask, newTask)) { + return true; + } + } + return false; + } + + private boolean isOverlapping(Task t1, Task t2) { + if (t1.getStartTime() == null || t2.getStartTime() == null) { + return false; + } + long t1StartEpoch = t1.getStartTime().toEpochSecond(ZoneOffset.UTC); + long t1EndEpoch = t1StartEpoch + t1.getDuration().getSeconds(); + long t2StartEpoch = t2.getStartTime().toEpochSecond(ZoneOffset.UTC); + long t2EndEpoch = t2StartEpoch + t2.getDuration().getSeconds(); + + return t1StartEpoch < t2EndEpoch && t2StartEpoch < t1EndEpoch; } private void updateEpicStatus(Epic epic) { @@ -218,7 +291,7 @@ private void updateEpicStatus(Epic epic) { allIsInNewCount++; } } - if (allIsDoneCount == list.size()) { + if (list.isEmpty() || allIsDoneCount == list.size()) { epic.setStatus(Status.DONE); } else if (allIsInNewCount == list.size()) { epic.setStatus(Status.NEW); @@ -226,4 +299,13 @@ private void updateEpicStatus(Epic epic) { epic.setStatus(Status.IN_PROGRESS); } } -} + + void validateTask(Task task) { + if (task.getName() == null || task.getName().isEmpty()) { + throw new IllegalArgumentException("Task name cannot be null or empty."); + } + if (task.getDescription() == null) { + throw new IllegalArgumentException("Task description cannot be null."); + } + } +} \ No newline at end of file diff --git a/src/manager/Node.java b/src/manager/Node.java new file mode 100644 index 0000000..4f9bb35 --- /dev/null +++ b/src/manager/Node.java @@ -0,0 +1,34 @@ +package manager; + +import model.Task; + +public class Node { + private Task task; + private manager.Node prev; + private manager.Node next; + + public manager.Node getNext() { + return next; + } + + public manager.Node getPrev() { + return prev; + } + + public Task getTask() { + return task; + } + + public void setNext(manager.Node next) { + this.next = next; + } + + public void setPrev(manager.Node prev) { + this.prev = prev; + } + + public void setTask(Task task) { + this.task = task; + } + } + diff --git a/src/manager/TaskManager.java b/src/manager/TaskManager.java index 917f3f8..f033444 100644 --- a/src/manager/TaskManager.java +++ b/src/manager/TaskManager.java @@ -1,6 +1,5 @@ package manager; - import model.Epic; import model.Subtask; import model.Task; @@ -10,23 +9,44 @@ public interface TaskManager { Task addTask(Task task); + Epic addEpic(Epic epic); + Subtask addSubtask(Subtask subtask); - Task updateTask(Task task); + + Task updateTask(Task updatedTask); + Epic updateEpic(Epic epic); + Subtask updateSubtask(Subtask subtask); + Task getTaskByID(int id); + Epic getEpicByID(int id); + Subtask getSubtaskByID(int id); + ArrayList getTasks(); + ArrayList getEpics(); + ArrayList getSubtasks(); + ArrayList getEpicSubtasks(Epic epic); + void deleteTasks(); + void deleteEpics(); + void deleteSubtasks(); + void deleteTaskByID(int id); + void deleteEpicByID(int id); + void deleteSubtaskByID(int id); + List getHistory(); -} + + List getPrioritizedTasks(); +} \ No newline at end of file diff --git a/src/model/Epic.java b/src/model/Epic.java index 3817186..b69b861 100644 --- a/src/model/Epic.java +++ b/src/model/Epic.java @@ -1,5 +1,9 @@ package model; +import tasktype.TaskType; + +import java.time.Duration; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Objects; @@ -8,15 +12,24 @@ public class Epic extends Task { public Epic(int id, String name, String description) { super(id, name, description); - // Статус NEW устанавливается по умолчанию в конструкторе родительского класса Task + } + + public Epic(int id, String name, String description, Status status, Duration duration, LocalDateTime startTime) { + super(id, name, description, status, duration, startTime); + } + + public Epic(int id, String name, String description, Duration duration, LocalDateTime startTime) { + super(id, name, description, Status.NEW, duration, startTime); } public void addSubtask(Subtask subtask) { subtaskList.add(subtask); + updateEpicDetails(); } public void clearSubtasks() { subtaskList.clear(); + updateEpicDetails(); } public ArrayList getSubtaskList() { @@ -25,6 +38,34 @@ public ArrayList getSubtaskList() { public void setSubtaskList(ArrayList subtaskList) { this.subtaskList = subtaskList; + updateEpicDetails(); + } + + private void updateEpicDetails() { + this.duration = Duration.ZERO; + this.startTime = null; + + if (!subtaskList.isEmpty()) { + LocalDateTime earliestStart = null; + LocalDateTime latestEnd = null; + + for (Subtask subtask : subtaskList) { + if (subtask.getStartTime() != null) { + if (earliestStart == null || subtask.getStartTime().isBefore(earliestStart)) { + earliestStart = subtask.getStartTime(); + } + if (latestEnd == null || subtask.getEndTime().isAfter(latestEnd)) { + latestEnd = subtask.getEndTime(); + } + } + if (subtask.getDuration() != null) { + this.duration = this.duration.plus(subtask.getDuration()); + } + } + + this.startTime = earliestStart; + + } } @Override @@ -35,17 +76,17 @@ public String toString() { ", id=" + getId() + ", subtaskList.size=" + subtaskList.size() + ", status=" + getStatus() + + ", duration=" + duration + + ", startTime=" + startTime + + ", endTime=" + getEndTime() + '}'; } + @Override public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; Epic other = (Epic) obj; return getId() == other.getId(); } @@ -54,4 +95,9 @@ public boolean equals(Object obj) { public int hashCode() { return Objects.hash(getId()); } + + @Override + public TaskType getType() { + return TaskType.EPIC; + } } \ No newline at end of file diff --git a/src/model/Subtask.java b/src/model/Subtask.java index 38410af..8d689ea 100644 --- a/src/model/Subtask.java +++ b/src/model/Subtask.java @@ -1,5 +1,11 @@ package model; +import tasktype.TaskType; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.Objects; + public class Subtask extends Task { private final int epicID; @@ -8,8 +14,13 @@ public Subtask(String name, String description, int epicID) { this.epicID = epicID; } - public Subtask(int id, String name, String description, Status status, int epicID) { - super(id, name, description, status); + public Subtask(int id, String name, String description, Status status, Duration duration, LocalDateTime startTime, int epicID) { + super(id, name, description, status, duration, startTime); + this.epicID = epicID; + } + + public Subtask(String name, String description, int epicID, Duration duration, LocalDateTime startTime) { + super(name, description, duration, startTime); this.epicID = epicID; } @@ -19,14 +30,17 @@ public int getEpicID() { @Override public String toString() { - return "model.Subtask{" + + return "Subtask{" + "name='" + getName() + '\'' + ", description='" + getDescription() + '\'' + ", id=" + getId() + ", epicID=" + epicID + ", status=" + getStatus() + + ", duration=" + getDuration() + + ", startTime=" + getStartTime() + '}'; } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -34,4 +48,14 @@ public boolean equals(Object o) { Subtask subtask = (Subtask) o; return epicID == subtask.epicID; } + + @Override + public int hashCode() { + return Objects.hash(epicID); + } + + @Override + public TaskType getType() { + return TaskType.SUBTASK; + } } \ No newline at end of file diff --git a/src/model/Task.java b/src/model/Task.java index e70661f..bb4332a 100644 --- a/src/model/Task.java +++ b/src/model/Task.java @@ -1,44 +1,83 @@ package model; +import tasktype.TaskType; + +import java.time.Duration; +import java.time.LocalDateTime; import java.util.Objects; public class Task { - private String name; - private String description; - private int id; - private Status status; + protected int id; + protected String name; + protected String description; + protected Status status; + protected Duration duration; + protected LocalDateTime startTime; - public Task(int id, String name, String description, Status status) { - this.id = id; + public Task(String name, String description) { this.name = name; this.description = description; - this.status = status; + this.status = Status.NEW; } - public Task(String name, String description) { + public Task(Task otherTask) { + this.id = otherTask.getId(); + this.name = otherTask.getName(); + this.description = otherTask.getDescription(); + this.status = otherTask.getStatus(); + this.duration = otherTask.getDuration(); + this.startTime = otherTask.getStartTime(); + } + + public Task(String name, String description, Duration duration, LocalDateTime startTime) { this.name = name; this.description = description; this.status = Status.NEW; + this.duration = duration; + this.startTime = startTime; } public Task(int id, String name, String description) { - this(id, name, description, Status.NEW); + this.id = id; + this.name = name; + this.description = description; + this.status = Status.NEW; } - public String getName() { - return name; + public Task(int id, String name, String description, Status status) { + this.id = id; + this.name = name; + this.description = description; + this.status = status; } - public void setName(String name) { + public Task(int id, String name, String description, Status status, Duration duration, LocalDateTime startTime) { + this.id = id; this.name = name; + this.description = description; + this.status = status; + this.duration = duration; + this.startTime = startTime; } - public String getDescription() { - return description; + public LocalDateTime getEndTime() { + return startTime != null && duration != null ? startTime.plus(duration) : null; } - public void setDescription(String description) { - this.description = description; + public Duration getDuration() { + return duration; + } + + public void setDuration(Duration duration) { + this.duration = duration; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; } public int getId() { @@ -49,6 +88,22 @@ public void setId(int id) { this.id = id; } + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + public Status getStatus() { return status; } @@ -58,34 +113,31 @@ public void setStatus(Status status) { } @Override - public boolean equals(Object object) { - if (this == object) return true; - if (object == null || getClass() != object.getClass()) return false; - Task task = (Task) object; - return id == task.id; + public String toString() { + return "Task{" + + "id=" + id + + ", name='" + name + '\'' + + ", description='" + description + '\'' + + ", status=" + status + + ", duration=" + duration + + ", startTime=" + startTime + + '}'; } @Override - public int hashCode() { - int hash = 17; - if (name != null) { - hash = hash + name.hashCode(); - } - hash = hash * 31; - if (description != null) { - hash = hash + description.hashCode(); - } - return hash; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Task task = (Task) o; + return id == task.id; } @Override - public String toString() { - return "model.Task{" + - "name='" + name + '\'' + - ", description='" + description + '\'' + - ", id=" + id + - ", status=" + status + - '}'; + public int hashCode() { + return Objects.hash(id); } + public TaskType getType() { + return TaskType.TASK; + } } \ No newline at end of file diff --git a/src/tasktype/TaskType.java b/src/tasktype/TaskType.java new file mode 100644 index 0000000..1405e80 --- /dev/null +++ b/src/tasktype/TaskType.java @@ -0,0 +1,7 @@ +package tasktype; + +public enum TaskType { + TASK, + EPIC, + SUBTASK +} \ No newline at end of file diff --git a/test/manager/FileBackedTaskManagerTest.java b/test/manager/FileBackedTaskManagerTest.java new file mode 100644 index 0000000..1923bc7 --- /dev/null +++ b/test/manager/FileBackedTaskManagerTest.java @@ -0,0 +1,103 @@ +package manager; + +import model.Epic; +import model.Subtask; +import model.Task; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class FileBackedTaskManagerTest extends TaskManagerTest { + private File file; + + @BeforeEach + public void setUp() { + file = new File("test_tasks.csv"); + taskManager = new FileBackedTaskManager(file); + } + + @AfterEach + public void tearDown() { + if (file.exists()) { + file.delete(); + } + } + + @Override + protected FileBackedTaskManager createTaskManager() { + return new FileBackedTaskManager(file); + } + + @Test + public void testSaveAndLoadFromFile() throws IOException { + LocalDateTime now = LocalDateTime.now(); + + Task task = new Task("Test Task", "Description", Duration.ofMinutes(30), now); + taskManager.addTask(task); + + Epic epic = new Epic(10, "Test Epic", "Epic Description"); + taskManager.addEpic(epic); + + Subtask subtask = new Subtask("Test Subtask", "Subtask Description", epic.getId(), Duration.ofMinutes(30), now.plusMinutes(40)); + taskManager.addSubtask(subtask); + + FileBackedTaskManager loadedManager = FileBackedTaskManager.loadFromFile(file); + + assertEquals(task, loadedManager.getTaskByID(task.getId())); + assertEquals(epic, loadedManager.getEpicByID(epic.getId())); + assertEquals(subtask, loadedManager.getSubtaskByID(subtask.getId())); + } + + @Test + public void testAddTaskAndCheckFileContent() throws IOException { + Task task = new Task("Test Task", "Description", Duration.ofMinutes(30), LocalDateTime.now()); + taskManager.addTask(task); + + List lines = Files.readAllLines(file.toPath()); + assertEquals(2, lines.size()); + assertTrue(lines.get(1).contains("Test Task")); + } + + @Test + public void testDeleteTaskAndCheckFileContent() throws IOException { + Task task = new Task("Test Task", "Description", Duration.ofMinutes(30), LocalDateTime.now()); + taskManager.addTask(task); + taskManager.deleteTaskByID(task.getId()); + + List lines = Files.readAllLines(file.toPath()); + assertEquals(1, lines.size()); + } + + @Test + public void testUpdateTaskAndCheckFileContent() throws IOException { + LocalDateTime now = LocalDateTime.now(); + + Task task = new Task("Test Task", "Description", Duration.ofMinutes(30), now); + taskManager.addTask(task); + + task.setDescription("Updated Description"); + taskManager.updateTask(task); + + List lines = Files.readAllLines(file.toPath()); + assertTrue(lines.get(1).contains("Updated Description")); + } + + @Test + public void testLoadFromFileWithEmptyFile() throws IOException { + file.createNewFile(); + + FileBackedTaskManager loadedManager = FileBackedTaskManager.loadFromFile(file); + assertTrue(loadedManager.getTasks().isEmpty()); + assertTrue(loadedManager.getEpics().isEmpty()); + assertTrue(loadedManager.getSubtasks().isEmpty()); + } +} \ No newline at end of file diff --git a/test/manager/InMemoryHistoryManagerTest.java b/test/manager/InMemoryHistoryManagerTest.java new file mode 100644 index 0000000..20056d2 --- /dev/null +++ b/test/manager/InMemoryHistoryManagerTest.java @@ -0,0 +1,93 @@ +package manager; + +import model.Epic; +import model.Status; +import model.Task; +import org.junit.jupiter.api.Test; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class InMemoryHistoryManagerTest { + + @Test + public void testEmptyHistory() { + InMemoryHistoryManager historyManager = new InMemoryHistoryManager(); + List history = historyManager.getHistory(); + assertEquals(0, history.size(), "History should be empty initially."); + } + + @Test + public void testDuplicateTask() { + InMemoryHistoryManager historyManager = new InMemoryHistoryManager(); + Task task = new Task(1, "Task1", "Description1", Status.NEW, Duration.ofMinutes(30), LocalDateTime.now()); + + + historyManager.add(task); + historyManager.add(task); + List history = historyManager.getHistory(); + + assertEquals(1, history.size(), "History should contain only one instance of the task."); + assertEquals(task, history.get(0), "The task in history should be the same as the added task."); + } + + @Test + public void testRemoveFromBeginning() { + InMemoryHistoryManager historyManager = new InMemoryHistoryManager(); + Task task1 = new Task(1, "Task1", "Description1", Status.NEW, Duration.ofMinutes(30), LocalDateTime.now()); + Task task2 = new Task(2, "Task2", "Description2", Status.NEW, Duration.ofMinutes(30), LocalDateTime.now()); + Task task3 = new Task(3, "Task3", "Description3", Status.NEW, Duration.ofMinutes(30), LocalDateTime.now()); + + historyManager.add(task1); + historyManager.add(task2); + historyManager.add(task3); + + historyManager.remove(1); + List history = historyManager.getHistory(); + + assertEquals(2, history.size(), "History should contain two tasks after removing the first one."); + assertEquals(task2, history.get(0), "The first task in history should now be Task2."); + assertEquals(task3, history.get(1), "The second task in history should still be Task3."); + } + + @Test + public void testRemoveFromMiddle() { + InMemoryHistoryManager historyManager = new InMemoryHistoryManager(); + Task task1 = new Task(1, "Task1", "Description1", Status.NEW, Duration.ofMinutes(30), LocalDateTime.now()); + Task task2 = new Task(2, "Task2", "Description2", Status.NEW, Duration.ofMinutes(30), LocalDateTime.now()); + Task task3 = new Task(3, "Task3", "Description3", Status.NEW, Duration.ofMinutes(30), LocalDateTime.now()); + + historyManager.add(task1); + historyManager.add(task2); + historyManager.add(task3); + + historyManager.remove(2); + List history = historyManager.getHistory(); + + assertEquals(2, history.size(), "History should contain two tasks after removing the second one."); + assertEquals(task1, history.get(0), "The first task in history should still be Task1."); + assertEquals(task3, history.get(1), "The second task in history should now be Task3."); + } + + @Test + public void testRemoveFromEnd() { + InMemoryHistoryManager historyManager = new InMemoryHistoryManager(); + Task task1 = new Task(1, "Task1", "Description1", Status.NEW, Duration.ofMinutes(30), LocalDateTime.now()); + Task task2 = new Task(2, "Task2", "Description2", Status.NEW, Duration.ofMinutes(30), LocalDateTime.now()); + Task task3 = new Task(3, "Task3", "Description3", Status.NEW, Duration.ofMinutes(30), LocalDateTime.now()); + + historyManager.add(task1); + historyManager.add(task2); + historyManager.add(task3); + + historyManager.remove(3); + List history = historyManager.getHistory(); + + assertEquals(2, history.size(), "History should contain two tasks after removing the last one."); + assertEquals(task1, history.get(0), "The first task in history should still be Task1."); + assertEquals(task2, history.get(1), "The second task in history should now be Task2."); + } +} \ No newline at end of file diff --git a/test/manager/InMemoryTaskManagerTest.java b/test/manager/InMemoryTaskManagerTest.java new file mode 100644 index 0000000..a633fe9 --- /dev/null +++ b/test/manager/InMemoryTaskManagerTest.java @@ -0,0 +1,67 @@ +package manager; + + +import model.Task; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + + + +import static org.junit.jupiter.api.Assertions.*; + +class InMemoryTaskManagerTest { + private InMemoryTaskManager taskManager; + + @BeforeEach + void setUp() { + taskManager = new InMemoryTaskManager(); + } + + @Test + void testAddTask() { + Task task = new Task("Test Task", "This is a test task"); + Task addedTask = taskManager.addTask(task); + assertNotNull(addedTask); + assertEquals("Test Task", addedTask.getName()); + assertEquals(1, addedTask.getId()); + } + + @Test + void testUpdateTask() { + Task task = new Task("Test Task", "This is a test task"); + taskManager.addTask(task); + task.setName("Updated Task"); + Task updatedTask = taskManager.updateTask(task); + assertNotNull(updatedTask); + assertEquals("Updated Task", updatedTask.getName()); + } + + @Test + void testGetTaskByID() { + Task task = new Task("Test Task", "This is a test task"); + taskManager.addTask(task); + Task retrievedTask = taskManager.getTaskByID(task.getId()); + assertNotNull(retrievedTask); + assertEquals(task.getId(), retrievedTask.getId()); + } + + @Test + void testDeleteTaskByID() { + Task task = new Task("Test Task", "This is a test task"); + taskManager.addTask(task); + taskManager.deleteTaskByID(task.getId()); + assertNull(taskManager.getTaskByID(task.getId())); + } + + @Test + void testDeleteTasks() { + Task task1 = new Task("Task 1", "Description 1"); + Task task2 = new Task("Task 2", "Description 2"); + taskManager.addTask(task1); + taskManager.addTask(task2); + taskManager.deleteTasks(); + assertTrue(taskManager.getTasks().isEmpty()); + } + + +} \ No newline at end of file diff --git a/Test/manager/ManagersTest.java b/test/manager/ManagersTest.java similarity index 100% rename from Test/manager/ManagersTest.java rename to test/manager/ManagersTest.java diff --git a/test/manager/TaskManagerTest.java b/test/manager/TaskManagerTest.java new file mode 100644 index 0000000..9f2b477 --- /dev/null +++ b/test/manager/TaskManagerTest.java @@ -0,0 +1,138 @@ +package manager; + +import model.Epic; +import model.Status; +import model.Subtask; +import model.Task; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public abstract class TaskManagerTest { + protected T taskManager; + + @BeforeEach + public void setUp() { + taskManager = createTaskManager(); + } + + protected abstract T createTaskManager(); + + @Test + public void testAddTask() { + Task task = new Task("Test Task", "Description", Duration.ofMinutes(30), LocalDateTime.now()); + taskManager.addTask(task); + assertEquals(task, taskManager.getTaskByID(task.getId())); + } + + @Test + public void testAddEpic() { + Epic epic = new Epic(10, "Test Epic", "Epic Description"); + taskManager.addEpic(epic); + assertEquals(epic, taskManager.getEpicByID(epic.getId())); + } + + @Test + public void testAddSubtask() { + Epic epic = new Epic(10, "Test Epic", "Epic Description"); + taskManager.addEpic(epic); + Subtask subtask = new Subtask("Test Subtask", "Subtask Description", epic.getId(), Duration.ofMinutes(30), LocalDateTime.now()); + taskManager.addSubtask(subtask); + assertEquals(subtask, taskManager.getSubtaskByID(subtask.getId())); + } + + @Test + public void testEpicStatusCalculation() { + Epic epic = new Epic(10, "Test Epic", "Epic Description"); + taskManager.addEpic(epic); + Subtask subtask1 = new Subtask("Subtask 1", "Description", epic.getId(), Duration.ofMinutes(30), LocalDateTime.now()); + Subtask subtask2 = new Subtask("Subtask 2", "Description", epic.getId(), Duration.ofMinutes(30), LocalDateTime.now()); + taskManager.addSubtask(subtask1); + taskManager.addSubtask(subtask2); + + assertEquals(Status.NEW, epic.getStatus()); + + subtask1.setStatus(Status.DONE); + taskManager.updateSubtask(subtask1); + + assertEquals(Status.IN_PROGRESS, epic.getStatus()); + + subtask2.setStatus(Status.DONE); + taskManager.updateSubtask(subtask2); + + assertEquals(Status.DONE, epic.getStatus()); + } + + @Test + public void testGetPrioritizedTasks() { + LocalDateTime now = LocalDateTime.now(); + + Task task1 = new Task("Task 1", "Description 1", Duration.ofMinutes(30), now.plusMinutes(10)); + Task task2 = new Task("Task 2", "Description 2", Duration.ofMinutes(30), now.plusMinutes(50)); + Task task3 = new Task("Task 3", "Description 3", Duration.ofMinutes(30), now.plusMinutes(90)); + + taskManager.addTask(task1); + taskManager.addTask(task2); + taskManager.addTask(task3); + + List prioritizedTasks = taskManager.getPrioritizedTasks(); + + assertEquals(3, prioritizedTasks.size()); + assertEquals(task1, prioritizedTasks.get(0)); + assertEquals(task2, prioritizedTasks.get(1)); + assertEquals(task3, prioritizedTasks.get(2)); + } + + @Test + public void testDeleteTaskByID() { + Task task = new Task("Test Task", "Description", Duration.ofMinutes(30), LocalDateTime.now()); + taskManager.addTask(task); + taskManager.deleteTaskByID(task.getId()); + assertNull(taskManager.getTaskByID(task.getId())); + } + + @Test + public void testDeleteEpicWithSubtasks() { + Epic epic = new Epic(10, "Test Epic", "Epic Description"); + taskManager.addEpic(epic); + Subtask subtask = new Subtask("Test Subtask", "Subtask Description", epic.getId(), Duration.ofMinutes(30), LocalDateTime.now()); + taskManager.addSubtask(subtask); + taskManager.deleteEpicByID(epic.getId()); + assertNull(taskManager.getEpicByID(epic.getId())); + assertNull(taskManager.getSubtaskByID(subtask.getId())); + } + + @Test + public void testUpdateTask() { + Task task = new Task("Test Task", "Description", Duration.ofMinutes(30), LocalDateTime.now()); + taskManager.addTask(task); + task.setDescription("Updated Description"); + taskManager.updateTask(task); + assertEquals("Updated Description", taskManager.getTaskByID(task.getId()).getDescription()); + } + + @Test + public void testUpdateEpic() { + Epic epic = new Epic(10, "Test Epic", "Epic Description"); + taskManager.addEpic(epic); + epic.setDescription("Updated Epic Description"); + taskManager.updateEpic(epic); + assertEquals("Updated Epic Description", taskManager.getEpicByID(epic.getId()).getDescription()); + } + + @Test + public void testUpdateSubtask() { + Epic epic = new Epic(10, "Test Epic", "Epic Description"); + taskManager.addEpic(epic); + Subtask subtask = new Subtask("Test Subtask", "Subtask Description", epic.getId(), Duration.ofMinutes(30), LocalDateTime.now()); + taskManager.addSubtask(subtask); + subtask.setDescription("Updated Subtask Description"); + taskManager.updateSubtask(subtask); + assertEquals("Updated Subtask Description", taskManager.getSubtaskByID(subtask.getId()).getDescription()); + } +} \ No newline at end of file diff --git a/Test/model/EpicTest.java b/test/model/EpicTest.java similarity index 100% rename from Test/model/EpicTest.java rename to test/model/EpicTest.java diff --git a/test/model/SubtaskTest.java b/test/model/SubtaskTest.java new file mode 100644 index 0000000..3a0fb96 --- /dev/null +++ b/test/model/SubtaskTest.java @@ -0,0 +1,31 @@ +package model; + +import org.junit.jupiter.api.Test; + + +import static org.junit.jupiter.api.Assertions.*; + +class SubtaskTest { + + @Test + void testEquals() { + Subtask subtask1 = new Subtask("Test Subtask", "This is a test subtask", 1); + Subtask subtask2 = new Subtask("Another Subtask", "This is another test subtask", 1); + Subtask subtask3 = new Subtask("Different Subtask", "This is a different test subtask", 2); + + assertEquals(subtask1, subtask2); + assertNotEquals(subtask1, subtask3); + } + + @Test + void testHashCode() { + Subtask subtask1 = new Subtask("Test Subtask", "This is a test subtask", 1); + Subtask subtask2 = new Subtask("Another Subtask", "This is another test subtask", 1); + Subtask subtask3 = new Subtask("Different Subtask", "This is a different test subtask", 2); + + assertEquals(subtask1.hashCode(), subtask2.hashCode()); + assertNotEquals(subtask1.hashCode(), subtask3.hashCode()); + } + + +} \ No newline at end of file diff --git a/Test/model/TaskTest.java b/test/model/TaskTest.java similarity index 100% rename from Test/model/TaskTest.java rename to test/model/TaskTest.java