From 260ec6ebf0af1d96211533b9e69bff4eb0621589 Mon Sep 17 00:00:00 2001 From: n20va Date: Thu, 10 Jul 2025 22:14:27 +0300 Subject: [PATCH 01/10] sprint 8 --- src/Main.java | 109 +++----- src/manager/FileBackedTaskManager.java | 217 +++++++++++++++ src/manager/HistoryManager.java | 4 + src/manager/InMemoryHistoryManager.java | 66 ++++- src/manager/InMemoryTaskManager.java | 252 ++++++++++++------ src/manager/Managers.java | 6 + src/manager/TaskManager.java | 16 +- src/model/Epic.java | 38 +-- src/model/Subtask.java | 19 +- src/model/Task.java | 83 ++++-- .../manager/FileBackedTaskManagerTest.java | 105 ++++++++ .../manager/InMemoryHistoryManagerTest.java | 60 +++++ .../manager/InMemoryTaskManagerTest.java | 13 +- src/test/model/EpicTest.java | 47 ++++ src/test/model/SubtaskTest.java | 47 ++++ src/test/model/TaskTest.java | 74 +++++ .../manager/InMemoryHistoryManagerTest.java | 65 ----- src/tests/model/EpicTest.java | 55 ---- src/tests/model/SubtaskTest.java | 19 -- src/tests/model/TaskTest.java | 95 ------- 20 files changed, 950 insertions(+), 440 deletions(-) create mode 100644 src/manager/FileBackedTaskManager.java create mode 100644 src/test/manager/FileBackedTaskManagerTest.java create mode 100644 src/test/manager/InMemoryHistoryManagerTest.java rename src/{tests => test}/manager/InMemoryTaskManagerTest.java (90%) create mode 100644 src/test/model/EpicTest.java create mode 100644 src/test/model/SubtaskTest.java create mode 100644 src/test/model/TaskTest.java delete mode 100644 src/tests/manager/InMemoryHistoryManagerTest.java delete mode 100644 src/tests/model/EpicTest.java delete mode 100644 src/tests/model/SubtaskTest.java delete mode 100644 src/tests/model/TaskTest.java diff --git a/src/Main.java b/src/Main.java index c4fd905..9592531 100644 --- a/src/Main.java +++ b/src/Main.java @@ -1,86 +1,53 @@ -import manager.InMemoryTaskManager; -import manager.Managers; +import manager.FileBackedTaskManager; import manager.TaskManager; -import model.Epic; -import model.Status; -import model.Subtask; -import model.Task; +import model.*; +import java.io.File; +import java.time.Duration; +import java.time.LocalDateTime; import java.util.List; public class Main { public static void main(String[] args) { - TaskManager taskManager = Managers.getDefault(); - - // Создаем задачи - Task task1 = new Task("Покупки", "Купить продукты", Status.NEW); - Task task2 = new Task("Тренировка", "Сходить в зал", Status.IN_PROGRESS); - taskManager.addTask(task1); - taskManager.addTask(task2); - - // Создаем эпик с подзадачами - Epic epic1 = new Epic("Проект", "Разработка нового функционала"); - taskManager.addEpic(epic1); - - Subtask subtask1 = new Subtask("Разработка интерфейса", "Создать макет UI", Status.NEW, epic1.getId()); - Subtask subtask2 = new Subtask("Тестирование", "Проверить функционал", Status.DONE, epic1.getId()); - taskManager.addSubtask(subtask1); - taskManager.addSubtask(subtask2); - - // Просматриваем задачи для наполнения истории - System.out.println("\n=== Просмотр задач ==="); - taskManager.getTaskById(task1.getId()); - taskManager.getEpicById(epic1.getId()); - taskManager.getSubtaskById(subtask1.getId()); - taskManager.getSubtaskById(subtask2.getId()); - taskManager.getTaskById(task2.getId()); - - // Выводим все задачи и историю - printAllTasks(taskManager); - - // Создаем больше задач для демонстрации ограничения истории - System.out.println("\n=== Создаем дополнительные задачи ==="); - for (int i = 3; i <= 12; i++) { - Task task = new Task("Задача " + i, "Описание " + i, Status.NEW); - taskManager.addTask(task); - taskManager.getTaskById(task.getId()); // Просматриваем задачу + File file = new File("tasks.csv"); + TaskManager manager = new FileBackedTaskManager(file); + + Task task1 = new Task("Task 1", "Simple task", + Status.NEW, Duration.ofMinutes(30), LocalDateTime.of(2025, 7, 1, 10, 0)); + Task task2 = new Task("Task 2", "Another task", + Status.NEW, Duration.ofMinutes(45), LocalDateTime.of(2025, 7, 1, 11, 0)); + manager.addTask(task1); + manager.addTask(task2); + + Epic epic = new Epic("Epic 1", "Epic with subtasks"); + manager.addEpic(epic); + + Subtask subtask1 = new Subtask("Subtask 1", "Part 1", + Status.NEW, epic.getId(), Duration.ofMinutes(60), LocalDateTime.of(2025, 7, 1, 9, 0)); + Subtask subtask2 = new Subtask("Subtask 2", "Part 2", + Status.DONE, epic.getId(), Duration.ofMinutes(90), LocalDateTime.of(2025, 7, 1, 13, 0)); + manager.addSubtask(subtask1); + manager.addSubtask(subtask2); + + System.out.println("=== Prioritized Tasks ==="); + for (Task task : manager.getPrioritizedTasks()) { + System.out.println(task + " | start=" + task.getStartTime() + " | end=" + task.getEndTime()); } - // Выводим историю после превышения лимита (10 элементов) - System.out.println("\n=== История после 12 просмотров ==="); - printHistory(taskManager); - } - - private static void printAllTasks(TaskManager manager) { - System.out.println("\n=== Все задачи ==="); - System.out.println("Задачи:"); - for (Task task : manager.getAllTasks()) { + TaskManager loadedManager = FileBackedTaskManager.loadFromFile(file); + System.out.println("\n=== Loaded Tasks ==="); + for (Task task : loadedManager.getAllTasks()) { System.out.println(task); } - System.out.println("\nЭпики:"); - for (Epic epic : manager.getAllEpics()) { - System.out.println(epic); - for (Task subtask : manager.getSubtasksOfEpic(epic.getId())) { - System.out.println("--> " + subtask); - } - } - System.out.println("\nПодзадачи:"); - for (Task subtask : manager.getAllSubtasks()) { - System.out.println(subtask); + + System.out.println("\n=== Loaded Epics ==="); + for (Epic e : loadedManager.getAllEpics()) { + System.out.println(e); } - System.out.println("\nИстория просмотров:"); - printHistory(manager); - } - private static void printHistory(TaskManager manager) { - List history = manager.getHistory(); - if (history.isEmpty()) { - System.out.println("История пуста"); - } else { - System.out.println("Последние " + history.size() + " просмотренных задач:"); - for (Task task : history) { - System.out.println(" - " + task.getTitle() + " (ID: " + task.getId() + ")"); - } + System.out.println("\n=== Loaded Subtasks ==="); + for (Subtask s : loadedManager.getAllSubtasks()) { + System.out.println(s); } } } \ No newline at end of file diff --git a/src/manager/FileBackedTaskManager.java b/src/manager/FileBackedTaskManager.java new file mode 100644 index 0000000..f4c4c7c --- /dev/null +++ b/src/manager/FileBackedTaskManager.java @@ -0,0 +1,217 @@ +package manager; + +import model.Epic; +import model.Subtask; +import model.Task; +import model.Status; + +import java.io.*; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.*; + +public class FileBackedTaskManager extends InMemoryTaskManager { + + private final File file; + + public FileBackedTaskManager(File file) { + this.file = file; + } + + protected void save() { + try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { + writer.write("id,type,name,status,description,epic,duration,startTime\n"); + + for (Task task : getAllTasks()) { + writer.write(toString(task) + "\n"); + } + for (Epic epic : getAllEpics()) { + writer.write(toString(epic) + "\n"); + } + for (Subtask subtask : getAllSubtasks()) { + writer.write(toString(subtask) + "\n"); + } + + writer.write("\n"); + String history = historyToString(getHistory()); + writer.write(history); + + } catch (IOException e) { + System.out.println("Ошибка при сохранении в файл: " + e.getMessage()); + } + } + + private String toString(Task task) { + StringBuilder sb = new StringBuilder(); + sb.append(task.getId()).append(","); + if (task instanceof Epic) { + sb.append("EPIC"); + } else if (task instanceof Subtask) { + sb.append("SUBTASK"); + } else { + sb.append("TASK"); + } + sb.append(","); + sb.append(task.getTitle()).append(","); + sb.append(task.getStatus()).append(","); + sb.append(task.getDescription()).append(","); + if (task instanceof Subtask) { + sb.append(((Subtask) task).getEpicId()); + } else { + sb.append(""); + } + sb.append(","); + sb.append(task.getDuration() != null ? task.getDuration().toMinutes() : "").append(","); + sb.append(task.getStartTime() != null ? task.getStartTime() : ""); + return sb.toString(); + } + + private List historyFromString(String value) { + List history = new ArrayList<>(); + if (value == null || value.isEmpty()) { + return history; + } + String[] ids = value.split(","); + for (String idStr : ids) { + history.add(Integer.parseInt(idStr)); + } + return history; + } + + private String historyToString(List history) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < history.size(); i++) { + sb.append(history.get(i).getId()); + if (i < history.size() - 1) { + sb.append(","); + } + } + return sb.toString(); + } + + + public static FileBackedTaskManager loadFromFile(File file) { + FileBackedTaskManager manager = new FileBackedTaskManager(file); + + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + String line = reader.readLine(); + + while ((line = reader.readLine()) != null && !line.isEmpty()) { + 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); + } + } + + String emptyLine = reader.readLine(); + + if (emptyLine != null) { + String historyLine = reader.readLine(); + if (historyLine != null && !historyLine.isEmpty()) { + List historyIds = manager.historyFromString(historyLine); + for (Integer id : historyIds) { + Task t = manager.getTaskById(id); + if (t != null) { + manager.historyManager.add(t); + } + } + } + } + + } catch (IOException e) { + System.out.println("Ошибка при загрузке из файла: " + e.getMessage()); + } + + return manager; + } + + private static Task fromString(String value) { + String[] parts = value.split(",", -1); + int id = Integer.parseInt(parts[0]); + String type = parts[1]; + String title = parts[2]; + Status status = Status.valueOf(parts[3]); + String description = parts[4]; + String epicIdStr = parts[5]; + String durationStr = parts[6]; + String startTimeStr = parts[7]; + + Duration duration = durationStr.isEmpty() ? null : Duration.ofMinutes(Long.parseLong(durationStr)); + LocalDateTime startTime = startTimeStr.isEmpty() ? null : LocalDateTime.parse(startTimeStr); + + switch (type) { + case "EPIC": + Epic epic = new Epic(title, description); + epic.setId(id); + epic.setStatus(status); + return epic; + case "SUBTASK": + Subtask subtask = new Subtask(title, description, status, Integer.parseInt(epicIdStr), duration, startTime); + subtask.setId(id); + return subtask; + case "TASK": + default: + Task task = new Task(title, description, status, duration, startTime); + task.setId(id); + return task; + } + } + + @Override + public void addTask(Task task) { + super.addTask(task); + save(); + } + + @Override + public void addEpic(Epic epic) { + super.addEpic(epic); + save(); + } + + @Override + public void addSubtask(Subtask subtask) { + super.addSubtask(subtask); + save(); + } + + @Override + public void updateTask(Task task) { + super.updateTask(task); + save(); + } + + @Override + public void updateEpic(Epic epic) { + super.updateEpic(epic); + save(); + } + + @Override + public void updateSubtask(Subtask subtask) { + super.updateSubtask(subtask); + save(); + } + + @Override + public void removeTaskById(int id) { + super.removeTaskById(id); + save(); + } + + @Override + public void removeEpicById(int id) { + super.removeEpicById(id); + save(); + } + + @Override + public void removeSubtaskById(int id) { + super.removeSubtaskById(id); + save(); + } +} \ No newline at end of file diff --git a/src/manager/HistoryManager.java b/src/manager/HistoryManager.java index 6070997..bfe6cfc 100644 --- a/src/manager/HistoryManager.java +++ b/src/manager/HistoryManager.java @@ -4,6 +4,10 @@ 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 4d91302..3609daa 100644 --- a/src/manager/InMemoryHistoryManager.java +++ b/src/manager/InMemoryHistoryManager.java @@ -1,25 +1,75 @@ package manager; import model.Task; -import java.util.ArrayList; -import java.util.List; +import java.util.*; + public class InMemoryHistoryManager implements HistoryManager { - private static final int MAX_HISTORY_SIZE = 10; - private final List history = new ArrayList<>(); + + protected static class Node { + Task task; + Node prev; + Node next; + + Node(Task task) { + this.task = task; + } + } + + private final Map historyMap = new HashMap<>(); + private Node head; + private Node tail; @Override public void add(Task task) { if (task == null) return; + int id = task.getId(); + remove(id); + linkLast(task); + } - history.add(task); - if (history.size() > MAX_HISTORY_SIZE) { - history.remove(0); + @Override + public void remove(int id) { + Node node = historyMap.remove(id); + if (node != null) { + removeNode(node); } } @Override public List getHistory() { - return new ArrayList<>(history); + List tasks = new ArrayList<>(); + Node current = head; + while (current != null) { + tasks.add(current.task); + current = current.next; + } + return tasks; + } + + private void linkLast(Task task) { + Node node = new Node(task); + if (tail == null) { + head = node; + } else { + tail.next = node; + node.prev = tail; + } + tail = node; + historyMap.put(task.getId(), node); + } + + private void removeNode(Node node) { + if (node.prev != null) { + node.prev.next = node.next; + } else { + head = node.next; + } + + if (node.next != null) { + node.next.prev = node.prev; + } else { + tail = node.prev; + } } } \ No newline at end of file diff --git a/src/manager/InMemoryTaskManager.java b/src/manager/InMemoryTaskManager.java index 05b4454..8fb1499 100644 --- a/src/manager/InMemoryTaskManager.java +++ b/src/manager/InMemoryTaskManager.java @@ -5,44 +5,65 @@ import model.Subtask; import model.Task; +import java.time.Duration; +import java.time.LocalDateTime; import java.util.*; public class InMemoryTaskManager implements TaskManager { - protected int nextId = 1; - protected final Map tasks = new HashMap<>(); protected final Map epics = new HashMap<>(); protected final Map subtasks = new HashMap<>(); - + protected final Set prioritizedTasks = new TreeSet<>(Comparator + .comparing(Task::getStartTime, Comparator.nullsLast(LocalDateTime::compareTo)) + .thenComparingInt(Task::getId)); + protected final List history = new ArrayList<>(); protected final HistoryManager historyManager = Managers.getDefaultHistory(); - private int generateId() { - return nextId++; - } + protected int nextId = 1; @Override public void addTask(Task task) { - task.setId(generateId()); + if (task == null) return; + if (task.getId() == 0) { + task.setId(nextId++); + } + if (checkTimeIntersection(task)) { + throw new IllegalArgumentException("Task time intersects with existing task"); + } tasks.put(task.getId(), task); + prioritizedTasks.add(task); } @Override public void addEpic(Epic epic) { - epic.setId(generateId()); + if (epic == null) return; + if (epic.getId() == 0) { + epic.setId(nextId++); + } epics.put(epic.getId(), epic); + updateEpicTimeAndDuration(epic); } @Override public void addSubtask(Subtask subtask) { - int epicId = subtask.getEpicId(); - Epic epic = epics.get(epicId); - if (epic != null) { - subtask.setId(generateId()); - subtasks.put(subtask.getId(), subtask); - epic.addSubtask(subtask); - updateEpicStatus(epicId); + if (subtask == null) return; + if (!epics.containsKey(subtask.getEpicId())) { + throw new IllegalArgumentException("Epic does not exist for subtask"); + } + if (subtask.getId() == 0) { + subtask.setId(nextId++); + } + if (checkTimeIntersection(subtask)) { + throw new IllegalArgumentException("Subtask time intersects with existing task"); } + subtasks.put(subtask.getId(), subtask); + prioritizedTasks.add(subtask); + + Epic epic = epics.get(subtask.getEpicId()); + epic.addSubtaskId(subtask.getId()); + updateEpicStatus(epic); + updateEpicTimeAndDuration(epic); } @Override @@ -63,66 +84,63 @@ public List getAllSubtasks() { @Override public Task getTaskById(int id) { Task task = tasks.get(id); - if (task != null) historyManager.add(task); + if (task != null) addToHistory(task); return task; } @Override public Epic getEpicById(int id) { Epic epic = epics.get(id); - if (epic != null) historyManager.add(epic); + if (epic != null) addToHistory(epic); return epic; } @Override public Subtask getSubtaskById(int id) { Subtask subtask = subtasks.get(id); - if (subtask != null) historyManager.add(subtask); + if (subtask != null) addToHistory(subtask); return subtask; } @Override public void updateTask(Task task) { - if (tasks.containsKey(task.getId())) { - tasks.put(task.getId(), task); + if (task == null || !tasks.containsKey(task.getId())) return; + if (checkTimeIntersection(task, task.getId())) { + throw new IllegalArgumentException("Task time intersects with existing task"); } + prioritizedTasks.remove(tasks.get(task.getId())); + tasks.put(task.getId(), task); + prioritizedTasks.add(task); } @Override public void updateEpic(Epic epic) { - int id = epic.getId(); - Epic oldEpic = epics.get(id); - if (oldEpic == null) { - throw new IllegalArgumentException("Эпик с id " + id + " не найден"); - } - oldEpic.setTitle(epic.getTitle()); - oldEpic.setDescription(epic.getDescription()); + if (epic == null || !epics.containsKey(epic.getId())) return; + epics.put(epic.getId(), epic); + updateEpicTimeAndDuration(epic); } - - @Override public void updateSubtask(Subtask subtask) { - int id = subtask.getId(); - if (!subtasks.containsKey(id)) { - throw new IllegalArgumentException("Подзадача с id " + id + " не найдена"); + if (subtask == null || !subtasks.containsKey(subtask.getId())) return; + if (checkTimeIntersection(subtask, subtask.getId())) { + throw new IllegalArgumentException("Subtask time intersects with existing task"); } + prioritizedTasks.remove(subtasks.get(subtask.getId())); + subtasks.put(subtask.getId(), subtask); + prioritizedTasks.add(subtask); - Subtask existingSubtask = subtasks.get(id); - if (subtask.getEpicId() != existingSubtask.getEpicId()) { - throw new IllegalArgumentException("Нельзя изменить epicId подзадачи"); - } - - subtasks.put(id, subtask); Epic epic = epics.get(subtask.getEpicId()); - if (epic != null) { - updateEpicStatus(epic.getId()); - } + updateEpicStatus(epic); + updateEpicTimeAndDuration(epic); } - @Override public void removeTaskById(int id) { - tasks.remove(id); + Task task = tasks.remove(id); + if (task != null) { + prioritizedTasks.remove(task); + removeFromHistory(task); + } } @Override @@ -130,8 +148,13 @@ public void removeEpicById(int id) { Epic epic = epics.remove(id); if (epic != null) { for (int subId : epic.getSubtaskIds()) { - subtasks.remove(subId); + Subtask subtask = subtasks.remove(subId); + if (subtask != null) { + prioritizedTasks.remove(subtask); + removeFromHistory(subtask); + } } + removeFromHistory(epic); } } @@ -139,79 +162,110 @@ public void removeEpicById(int id) { public void removeSubtaskById(int id) { Subtask subtask = subtasks.remove(id); if (subtask != null) { + prioritizedTasks.remove(subtask); Epic epic = epics.get(subtask.getEpicId()); if (epic != null) { - epic.removeSubtask(id); - updateEpicStatus(epic.getId()); + epic.removeSubtaskId(id); + updateEpicStatus(epic); + updateEpicTimeAndDuration(epic); } + removeFromHistory(subtask); } } @Override public void clearTasks() { + for (Task task : tasks.values()) { + prioritizedTasks.remove(task); + } tasks.clear(); } @Override public void clearEpics() { + for (Epic epic : epics.values()) { + for (int subId : epic.getSubtaskIds()) { + Subtask subtask = subtasks.remove(subId); + if (subtask != null) { + prioritizedTasks.remove(subtask); + } + } + removeFromHistory(epic); + } epics.clear(); - subtasks.clear(); } @Override public void clearSubtasks() { + for (Subtask subtask : subtasks.values()) { + prioritizedTasks.remove(subtask); + } subtasks.clear(); for (Epic epic : epics.values()) { epic.getSubtaskIds().clear(); - updateEpicStatus(epic.getId()); + updateEpicStatus(epic); + updateEpicTimeAndDuration(epic); } } @Override public List getSubtasksOfEpic(int epicId) { - List result = new ArrayList<>(); Epic epic = epics.get(epicId); - if (epic != null) { - for (int subId : epic.getSubtaskIds()) { - Subtask subtask = subtasks.get(subId); - if (subtask != null) { - result.add(subtask); - } + if (epic == null) return Collections.emptyList(); + List list = new ArrayList<>(); + for (int id : epic.getSubtaskIds()) { + Subtask subtask = subtasks.get(id); + if (subtask != null) { + list.add(subtask); } } - return result; + return list; } - @Override public List getHistory() { - return historyManager.getHistory(); + return new ArrayList<>(history); } - private void updateEpicStatus(int epicId) { - Epic epic = epics.get(epicId); - if (epic == null) return; + @Override + public List getPrioritizedTasks() { + return new ArrayList<>(prioritizedTasks); + } + + private boolean checkTimeIntersection(Task newTask) { + return checkTimeIntersection(newTask, -1); + } - List subtaskIds = epic.getSubtaskIds(); - if (subtaskIds.isEmpty()) { + private boolean checkTimeIntersection(Task newTask, int ignoreId) { + if (newTask.getStartTime() == null || newTask.getDuration() == null) { + return false; + } + LocalDateTime newStart = newTask.getStartTime(); + LocalDateTime newEnd = newTask.getEndTime(); + + for (Task task : prioritizedTasks) { + if (task.getId() == ignoreId) continue; + if (task.getStartTime() == null || task.getDuration() == null) continue; + LocalDateTime start = task.getStartTime(); + LocalDateTime end = task.getEndTime(); + + boolean intersect = newStart.isBefore(end) && newEnd.isAfter(start); + if (intersect) { + return true; + } + } + return false; + } + + private void updateEpicStatus(Epic epic) { + List subtasksOfEpic = getSubtasksOfEpic(epic.getId()); + if (subtasksOfEpic.isEmpty()) { epic.setStatus(Status.NEW); return; } - boolean allNew = true; - boolean allDone = true; - - for (int id : subtaskIds) { - Subtask subtask = subtasks.get(id); - if (subtask == null) continue; - - if (subtask.getStatus() != Status.NEW) { - allNew = false; - } - if (subtask.getStatus() != Status.DONE) { - allDone = false; - } - } + boolean allNew = subtasksOfEpic.stream().allMatch(s -> s.getStatus() == Status.NEW); + boolean allDone = subtasksOfEpic.stream().allMatch(s -> s.getStatus() == Status.DONE); if (allNew) { epic.setStatus(Status.NEW); @@ -221,4 +275,48 @@ private void updateEpicStatus(int epicId) { epic.setStatus(Status.IN_PROGRESS); } } + + private void updateEpicTimeAndDuration(Epic epic) { + List subtasksOfEpic = getSubtasksOfEpic(epic.getId()); + + if (subtasksOfEpic.isEmpty()) { + epic.setDuration(Duration.ZERO); + epic.setStartTime(null); + return; + } + + Duration totalDuration = Duration.ZERO; + LocalDateTime earliestStart = null; + LocalDateTime latestEnd = null; + + for (Subtask sub : subtasksOfEpic) { + if (sub.getDuration() != null) { + totalDuration = totalDuration.plus(sub.getDuration()); + } + if (sub.getStartTime() != null) { + if (earliestStart == null || sub.getStartTime().isBefore(earliestStart)) { + earliestStart = sub.getStartTime(); + } + LocalDateTime subEnd = sub.getEndTime(); + if (subEnd != null && (latestEnd == null || subEnd.isAfter(latestEnd))) { + latestEnd = subEnd; + } + } + } + + epic.setDuration(totalDuration); + epic.setStartTime(earliestStart); + } + + private void addToHistory(Task task) { + history.remove(task); + history.add(task); + if (history.size() > 10) { + history.remove(0); + } + } + + private void removeFromHistory(Task task) { + history.remove(task); + } } \ No newline at end of file diff --git a/src/manager/Managers.java b/src/manager/Managers.java index 64dfb6f..71ee949 100644 --- a/src/manager/Managers.java +++ b/src/manager/Managers.java @@ -1,5 +1,7 @@ package manager; +import java.io.File; + public class Managers { public static TaskManager getDefault() { @@ -9,4 +11,8 @@ public static TaskManager getDefault() { public static HistoryManager getDefaultHistory() { return new InMemoryHistoryManager(); } + + public static TaskManager getFileBackedTaskManager(File file) { + return new FileBackedTaskManager(file); + } } \ No newline at end of file diff --git a/src/manager/TaskManager.java b/src/manager/TaskManager.java index 9a4c891..d97556d 100644 --- a/src/manager/TaskManager.java +++ b/src/manager/TaskManager.java @@ -1,38 +1,52 @@ package manager; -import model.Task; import model.Epic; import model.Subtask; +import model.Task; import java.util.List; public interface TaskManager { void addTask(Task task); + void addEpic(Epic epic); + void addSubtask(Subtask subtask); List getAllTasks(); + List getAllEpics(); + List getAllSubtasks(); Task getTaskById(int id); + Epic getEpicById(int id); + Subtask getSubtaskById(int id); void updateTask(Task task); + void updateEpic(Epic epic); + void updateSubtask(Subtask subtask); void removeTaskById(int id); + void removeEpicById(int id); + void removeSubtaskById(int id); void clearTasks(); + void clearEpics(); + void clearSubtasks(); List getSubtasksOfEpic(int epicId); List getHistory(); + + List getPrioritizedTasks(); } \ No newline at end of file diff --git a/src/model/Epic.java b/src/model/Epic.java index bdbde3d..413dc68 100644 --- a/src/model/Epic.java +++ b/src/model/Epic.java @@ -1,41 +1,45 @@ package model; +import java.time.Duration; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; -import java.util.Objects; public class Epic extends Task { - private final List subtaskIds = new ArrayList<>(); + private List subtaskIds = new ArrayList<>(); public Epic(String title, String description) { - super(title, description, Status.NEW); + super(title, description, Status.NEW, Duration.ZERO, null); } + public List getSubtaskIds() { return subtaskIds; } - public void addSubtask(Subtask subtask) { - subtaskIds.add(subtask.getId()); + public void addSubtaskId(int id) { + subtaskIds.add(id); } - public void removeSubtask(int subtaskId) { - subtaskIds.remove((Integer) subtaskId); + public void removeSubtaskId(int id) { + subtaskIds.remove(Integer.valueOf(id)); } @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof Epic)) return false; - if (!super.equals(o)) return false; - Epic epic = (Epic) o; - return Objects.equals(subtaskIds, epic.subtaskIds); + public Duration getDuration() { + return super.getDuration(); } @Override - public int hashCode() { - return Objects.hash(super.hashCode(), subtaskIds); + public LocalDateTime getStartTime() { + return super.getStartTime(); } + + @Override + public LocalDateTime getEndTime() { + return super.getEndTime(); + } + @Override public String toString() { return "Epic{" + @@ -43,7 +47,11 @@ public String toString() { ", title='" + getTitle() + '\'' + ", description='" + getDescription() + '\'' + ", status=" + getStatus() + + ", duration=" + (getDuration() != null ? getDuration().toMinutes() : "null") + + ", startTime=" + getStartTime() + ", subtaskIds=" + subtaskIds + '}'; } + + } \ No newline at end of file diff --git a/src/model/Subtask.java b/src/model/Subtask.java index 0b4eef5..5ea97ba 100644 --- a/src/model/Subtask.java +++ b/src/model/Subtask.java @@ -1,10 +1,13 @@ package model; +import java.time.Duration; +import java.time.LocalDateTime; + public class Subtask extends Task { - private final int epicId; + private int epicId; - public Subtask(String title, String description, Status status, int epicId) { - super(title, description, status); + public Subtask(String title, String description, Status status, int epicId, Duration duration, LocalDateTime startTime) { + super(title, description, status, duration, startTime); this.epicId = epicId; } @@ -12,14 +15,20 @@ public int getEpicId() { return epicId; } + public void setEpicId(int epicId) { + this.epicId = epicId; + } + @Override public String toString() { return "Subtask{" + - "id=" + getId() + + "epicId=" + epicId + + ", id=" + getId() + ", title='" + getTitle() + '\'' + ", description='" + getDescription() + '\'' + ", status=" + getStatus() + - ", epicId=" + epicId + + ", duration=" + (getDuration() != null ? getDuration().toMinutes() : "null") + + ", startTime=" + getStartTime() + '}'; } } \ No newline at end of file diff --git a/src/model/Task.java b/src/model/Task.java index 79a3730..c89496c 100644 --- a/src/model/Task.java +++ b/src/model/Task.java @@ -1,43 +1,78 @@ package model; - -import java.util.Objects; +import java.time.Duration; +import java.time.LocalDateTime; public class Task { private int id; private String title; private String description; private Status status; + private Duration duration; + private LocalDateTime startTime; - public Task(String title, String description, Status status) { + public Task(String title, String description, Status status, Duration duration, LocalDateTime startTime) { this.title = title; this.description = description; this.status = status; + this.duration = duration; + this.startTime = startTime; } - public int getId() { return id; } - public void setId(int id) { this.id = id; } - public String getTitle() { return title; } - public void setTitle(String title) { this.title = title; } - public String getDescription() { return description; } - public void setDescription(String description) { this.description = description; } - public Status getStatus() { return status; } - public void setStatus(Status status) { this.status = status; } + public int getId() { + return id; + } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof Task)) return false; - Task task = (Task) o; - return id == task.id && - Objects.equals(title, task.title) && - Objects.equals(description, task.description) && - status == task.status; + public void setId(int id) { + this.id = id; } - @Override - public int hashCode() { - return Objects.hash(id, title, description, status); + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Status getStatus() { + return status; + } + + public void setStatus(Status status) { + this.status = status; + } + + 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 LocalDateTime getEndTime() { + if (startTime != null && duration != null) { + return startTime.plus(duration); + } + return null; } @Override @@ -47,6 +82,8 @@ public String toString() { ", title='" + title + '\'' + ", description='" + description + '\'' + ", status=" + status + + ", duration=" + (duration != null ? duration.toMinutes() : "null") + + ", startTime=" + startTime + '}'; } } \ No newline at end of file diff --git a/src/test/manager/FileBackedTaskManagerTest.java b/src/test/manager/FileBackedTaskManagerTest.java new file mode 100644 index 0000000..7b968ff --- /dev/null +++ b/src/test/manager/FileBackedTaskManagerTest.java @@ -0,0 +1,105 @@ +package test.manager; + +import manager.FileBackedTaskManager; +import manager.TaskManager; +import model.Epic; +import model.Status; +import model.Subtask; +import model.Task; +import org.junit.jupiter.api.*; + +import java.io.File; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class FileBackedTaskManagerTest { + + static File file; + TaskManager manager; + + @BeforeAll + static void beforeAll() { + file = new File("test_data.csv"); + } + + @BeforeEach + void setUp() { + manager = new FileBackedTaskManager(file); + manager.clearTasks(); + manager.clearEpics(); + manager.clearSubtasks(); + } + + @AfterEach + void tearDown() { + if (file.exists()) { + file.delete(); + } + } + + @Test + public void testSaveAndLoad() { + Task task = new Task("Task 1", "Description 1", Status.NEW, + Duration.ofMinutes(30), LocalDateTime.of(2025, 7, 1, 9, 0)); + manager.addTask(task); + + Epic epic = new Epic("Epic 1", "Epic description"); + manager.addEpic(epic); + + Subtask subtask1 = new Subtask("Subtask 1", "Part 1", Status.NEW, + epic.getId(), Duration.ofMinutes(60), LocalDateTime.of(2025, 7, 1, 10, 0)); + Subtask subtask2 = new Subtask("Subtask 2", "Part 2", Status.DONE, + epic.getId(), Duration.ofMinutes(90), LocalDateTime.of(2025, 7, 1, 12, 0)); + manager.addSubtask(subtask1); + manager.addSubtask(subtask2); + + manager.getTaskById(task.getId()); + manager.getEpicById(epic.getId()); + manager.getSubtaskById(subtask1.getId()); + + TaskManager loadedManager = FileBackedTaskManager.loadFromFile(file); + + Task loadedTask = loadedManager.getTaskById(task.getId()); + assertNotNull(loadedTask); + assertEquals(task.getTitle(), loadedTask.getTitle()); + assertEquals(task.getDuration(), loadedTask.getDuration()); + assertEquals(task.getStartTime(), loadedTask.getStartTime()); + + Epic loadedEpic = loadedManager.getEpicById(epic.getId()); + assertNotNull(loadedEpic); + assertEquals(epic.getTitle(), loadedEpic.getTitle()); + + List loadedSubtasks = loadedManager.getSubtasksOfEpic(epic.getId()); + assertEquals(2, loadedSubtasks.size()); + + Subtask loadedSubtask1 = loadedManager.getSubtaskById(subtask1.getId()); + assertEquals(subtask1.getDuration(), loadedSubtask1.getDuration()); + assertEquals(subtask1.getStartTime(), loadedSubtask1.getStartTime()); + + List history = loadedManager.getHistory(); + assertEquals(3, history.size()); + assertEquals(task.getId(), history.get(0).getId()); + assertEquals(epic.getId(), history.get(1).getId()); + assertEquals(subtask1.getId(), history.get(2).getId()); + } + + @Test + public void testLoadFromCorruptedFile() { + try { + java.nio.file.Files.writeString(file.toPath(), "Not a valid CSV content\n"); + } catch (Exception e) { + fail("Не удалось записать тестовый файл"); + } + + TaskManager loadedManager = FileBackedTaskManager.loadFromFile(file); + assertNotNull(loadedManager); + assertTrue(loadedManager.getAllTasks().isEmpty()); + assertTrue(loadedManager.getAllEpics().isEmpty()); + assertTrue(loadedManager.getAllSubtasks().isEmpty()); + assertTrue(loadedManager.getHistory().isEmpty()); + } + +} \ No newline at end of file diff --git a/src/test/manager/InMemoryHistoryManagerTest.java b/src/test/manager/InMemoryHistoryManagerTest.java new file mode 100644 index 0000000..b1f7243 --- /dev/null +++ b/src/test/manager/InMemoryHistoryManagerTest.java @@ -0,0 +1,60 @@ +package test.manager; + +import manager.InMemoryHistoryManager; +import model.Task; +import model.Status; +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.*; + +class InMemoryHistoryManagerTest { + private InMemoryHistoryManager historyManager; + + @BeforeEach + void setUp() { + historyManager = new InMemoryHistoryManager(); + } + + @Test + void shouldAddAndReturnHistory() { + Task task = new Task("Test task", "Description", Status.NEW, Duration.ofMinutes(30), LocalDateTime.now()); + task.setId(1); + + historyManager.add(task); + List history = historyManager.getHistory(); + + assertEquals(1, history.size()); + assertEquals(task, history.get(0)); + } + + @Test + void shouldNotAddDuplicates() { + Task task = new Task("Task", "Desc", Status.NEW, Duration.ofMinutes(20), LocalDateTime.now()); + task.setId(1); + historyManager.add(task); + historyManager.add(task); + + assertEquals(1, historyManager.getHistory().size()); + } + + @Test + void shouldRemoveFromHistory() { + Task task1 = new Task("Task 1", "Desc 1", Status.NEW, Duration.ofMinutes(10), LocalDateTime.now()); + task1.setId(1); + Task task2 = new Task("Task 2", "Desc 2", Status.NEW, Duration.ofMinutes(10), LocalDateTime.now()); + task2.setId(2); + + historyManager.add(task1); + historyManager.add(task2); + historyManager.remove(1); + + List history = historyManager.getHistory(); + assertEquals(1, history.size()); + assertEquals(task2, history.get(0)); + } +} diff --git a/src/tests/manager/InMemoryTaskManagerTest.java b/src/test/manager/InMemoryTaskManagerTest.java similarity index 90% rename from src/tests/manager/InMemoryTaskManagerTest.java rename to src/test/manager/InMemoryTaskManagerTest.java index 7792d5d..36b0f48 100644 --- a/src/tests/manager/InMemoryTaskManagerTest.java +++ b/src/test/manager/InMemoryTaskManagerTest.java @@ -1,4 +1,4 @@ -package tests.manager; +package test.manager; import manager.InMemoryTaskManager; import model.Epic; @@ -8,6 +8,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.time.Duration; import java.util.List; import static org.junit.jupiter.api.Assertions.*; @@ -23,7 +24,7 @@ public void setUp() { @Test public void testAddAndGetTask() { - Task task = new Task("Task 1", "Description task 1", Status.NEW); + Task task = new Task("Task 1", "Description task 1", Status.NEW, Duration.ZERO, null); manager.addTask(task); List tasks = manager.getAllTasks(); @@ -46,7 +47,7 @@ public void testAddAndGetSubtask() { Epic epic = new Epic("Epic 1", "Description epic 1"); manager.addEpic(epic); - Subtask subtask = new Subtask("Subtask 1", "Description subtask 1", Status.NEW, epic.getId()); + Subtask subtask = new Subtask("Subtask 1", "Description subtask 1", Status.NEW, epic.getId(), Duration.ZERO, null); manager.addSubtask(subtask); List subtasks = manager.getAllSubtasks(); @@ -59,7 +60,7 @@ public void testAddAndGetSubtask() { @Test public void testRemoveTask() { - Task task = new Task("Task 1", "Description task 1", Status.NEW); + Task task = new Task("Task 1", "Description task 1", Status.NEW, Duration.ZERO, null); manager.addTask(task); manager.removeTaskById(task.getId()); @@ -71,7 +72,7 @@ public void testRemoveEpicAlsoRemovesSubtasks() { Epic epic = new Epic("Epic 1", "Description epic 1"); manager.addEpic(epic); - Subtask subtask = new Subtask("Subtask 1", "Description subtask 1", Status.NEW, epic.getId()); + Subtask subtask = new Subtask("Subtask 1", "Description subtask 1", Status.NEW, epic.getId(), Duration.ZERO, null); manager.addSubtask(subtask); manager.removeEpicById(epic.getId()); @@ -83,7 +84,7 @@ public void testRemoveEpicAlsoRemovesSubtasks() { @Test public void testUpdateTask() { - Task task = new Task("Task 1", "Description task 1", Status.NEW); + Task task = new Task("Task 1", "Description task 1", Status.NEW, Duration.ZERO, null); manager.addTask(task); task.setStatus(Status.DONE); diff --git a/src/test/model/EpicTest.java b/src/test/model/EpicTest.java new file mode 100644 index 0000000..a851659 --- /dev/null +++ b/src/test/model/EpicTest.java @@ -0,0 +1,47 @@ +package test.model; + +import model.Epic; +import model.Status; +import model.Subtask; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.time.Duration; +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.*; + +public class EpicTest { + + private Epic epic; + private Subtask s1; + private Subtask s2; + + @BeforeEach + public void setUp() { + epic = new Epic("Epic Title", "Epic Description"); + } + + @Test + public void shouldReturnNewStatusIfAllSubtasksNew() { + Subtask s1 = new Subtask("Sub1", "Desc1", Status.NEW, epic.getId(), + Duration.ofMinutes(30), LocalDateTime.of(2025, 7, 1, 10, 0)); + Subtask s2 = new Subtask("Sub2", "Desc2", Status.NEW, epic.getId(), + Duration.ofMinutes(60), LocalDateTime.of(2025, 7, 1, 12, 0)); + + epic.addSubtaskId(s1.getEpicId()); + epic.addSubtaskId(s2.getEpicId()); + + assertEquals(Status.NEW, epic.getStatus()); + } + + + + @Test + void epicIsCreatedWithEmptySubtaskList() { + assertNotNull(epic.getSubtaskIds()); + assertTrue(epic.getSubtaskIds().isEmpty()); + } + + +} \ No newline at end of file diff --git a/src/test/model/SubtaskTest.java b/src/test/model/SubtaskTest.java new file mode 100644 index 0000000..a56aba1 --- /dev/null +++ b/src/test/model/SubtaskTest.java @@ -0,0 +1,47 @@ +package test.model; + +import model.Status; +import model.Subtask; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.time.Duration; +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.*; + +class SubtaskTest { + + private Subtask subtask; + + @BeforeEach + void setUp() { + subtask = new Subtask("Subtask 1", "Subtask Description", Status.IN_PROGRESS, 10, Duration.ZERO, null); + subtask.setId(2); + subtask.setDuration(Duration.ofMinutes(45)); + subtask.setStartTime(LocalDateTime.of(2025, 7, 10, 11, 0)); + } + + @Test + void testGettersAndSetters() { + assertEquals(2, subtask.getId()); + assertEquals("Subtask 1", subtask.getTitle()); + assertEquals("Subtask Description", subtask.getDescription()); + assertEquals(Status.IN_PROGRESS, subtask.getStatus()); + assertEquals(10, subtask.getEpicId()); + assertEquals(Duration.ofMinutes(45), subtask.getDuration()); + assertEquals(LocalDateTime.of(2025, 7, 10, 11, 0), subtask.getStartTime()); + } + + @Test + void testGetEndTimeCalculation() { + LocalDateTime expectedEnd = subtask.getStartTime().plus(subtask.getDuration()); + assertEquals(expectedEnd, subtask.getEndTime()); + } + + @Test + void testToStringContainsEpicId() { + String toString = subtask.toString(); + assertTrue(toString.contains("epicId=10")); + } +} \ No newline at end of file diff --git a/src/test/model/TaskTest.java b/src/test/model/TaskTest.java new file mode 100644 index 0000000..4013ac6 --- /dev/null +++ b/src/test/model/TaskTest.java @@ -0,0 +1,74 @@ +package test.model; + +import model.Status; +import model.Task; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.time.Duration; +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.*; + +public class TaskTest { + + private Task task; + + @BeforeEach + public void setUp() { + task = new Task( + "Test Task", + "Description of test task", + Status.NEW, + Duration.ofMinutes(120), + LocalDateTime.of(2025, 7, 10, 9, 0) + ); + } + + @Test + public void shouldCreateTaskWithCorrectFields() { + assertEquals("Test Task", task.getTitle()); + assertEquals("Description of test task", task.getDescription()); + assertEquals(Status.NEW, task.getStatus()); + assertEquals(Duration.ofMinutes(120), task.getDuration()); + assertEquals(LocalDateTime.of(2025, 7, 10, 9, 0), task.getStartTime()); + } + + @Test + public void shouldCalculateEndTimeCorrectly() { + LocalDateTime expectedEndTime = LocalDateTime.of(2025, 7, 10, 11, 0); + assertEquals(expectedEndTime, task.getEndTime()); + } + + @Test + public void shouldUpdateStatus() { + task.setStatus(Status.IN_PROGRESS); + assertEquals(Status.IN_PROGRESS, task.getStatus()); + } + + @Test + public void shouldUpdateStartTimeAndDuration() { + task.setStartTime(LocalDateTime.of(2025, 7, 10, 10, 0)); + task.setDuration(Duration.ofMinutes(30)); + + assertEquals(LocalDateTime.of(2025, 7, 10, 10, 0), task.getStartTime()); + assertEquals(Duration.ofMinutes(30), task.getDuration()); + assertEquals(LocalDateTime.of(2025, 7, 10, 10, 30), task.getEndTime()); + } + + @Test + public void toStringShouldContainAllFields() { + String str = task.toString(); + + assertNotNull(str); + assertFalse(str.isEmpty()); + + assertTrue(str.contains(task.getTitle())); + assertTrue(str.contains(task.getDescription())); + assertTrue(str.contains(task.getStatus().toString())); + + assertTrue(str.contains(String.valueOf(task.getDuration().toMinutes()))); + + assertTrue(str.contains(task.getStartTime().toString())); + } +} \ No newline at end of file diff --git a/src/tests/manager/InMemoryHistoryManagerTest.java b/src/tests/manager/InMemoryHistoryManagerTest.java deleted file mode 100644 index 9eb7be6..0000000 --- a/src/tests/manager/InMemoryHistoryManagerTest.java +++ /dev/null @@ -1,65 +0,0 @@ -package tests.manager; - -import manager.HistoryManager; -import manager.InMemoryHistoryManager; -import model.Task; -import model.Status; -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 HistoryManager historyManager; - - @BeforeEach - void setUp() { - historyManager = new InMemoryHistoryManager(); - } - - @Test - void addAndGetHistory() { - Task task1 = new Task("Task1", "Desc", Status.NEW); - task1.setId(1); - Task task2 = new Task("Task2", "Desc", Status.IN_PROGRESS); - task2.setId(2); - - historyManager.add(task1); - historyManager.add(task2); - - List history = historyManager.getHistory(); - assertEquals(2, history.size()); - assertEquals(task1, history.get(0)); - assertEquals(task2, history.get(1)); - } - - @Test - void addSameTaskTwice() { - Task task = new Task("Task", "Desc", Status.NEW); - task.setId(1); - - historyManager.add(task); - historyManager.add(task); - - List history = historyManager.getHistory(); - assertEquals(2, history.size()); - assertEquals(task, history.get(0)); - assertEquals(task, history.get(1)); - } - - @Test - void historyLimit() { - for (int i = 1; i <= 15; i++) { - Task task = new Task("Task" + i, "Desc", Status.NEW); - task.setId(i); - historyManager.add(task); - } - - List history = historyManager.getHistory(); - assertEquals(10, history.size()); - assertEquals(6, history.get(0).getId()); - assertEquals(15, history.get(9).getId()); - } -} \ No newline at end of file diff --git a/src/tests/model/EpicTest.java b/src/tests/model/EpicTest.java deleted file mode 100644 index 9f24042..0000000 --- a/src/tests/model/EpicTest.java +++ /dev/null @@ -1,55 +0,0 @@ -package tests.model; - -import model.Epic; -import model.Status; -import model.Subtask; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - -class EpicTest { - private Epic epic; - private Subtask subtask1; - private Subtask subtask2; - - @BeforeEach - void setUp() { - epic = new Epic("Epic Title", "Epic Description"); - - subtask1 = new Subtask("Subtask 1", "Description 1", Status.NEW, epic.getId()); - subtask2 = new Subtask("Subtask 2", "Description 2", Status.NEW, epic.getId()); - - subtask1.setId(1); - subtask2.setId(2); - } - - @Test - void epicIsCreatedWithEmptySubtaskList() { - assertNotNull(epic.getSubtaskIds()); - assertTrue(epic.getSubtaskIds().isEmpty()); - } - - @Test - void addSubtask_addsIdToList() { - epic.addSubtask(subtask1); - epic.addSubtask(subtask2); - - assertEquals(2, epic.getSubtaskIds().size()); - assertTrue(epic.getSubtaskIds().contains(subtask1.getId())); - assertTrue(epic.getSubtaskIds().contains(subtask2.getId())); - } - - @Test - void removeSubtask_removesCorrectId() { - epic.addSubtask(subtask1); - epic.addSubtask(subtask2); - - epic.removeSubtask(subtask1.getId()); - - assertEquals(1, epic.getSubtaskIds().size()); - assertFalse(epic.getSubtaskIds().contains(subtask1.getId())); - assertTrue(epic.getSubtaskIds().contains(subtask2.getId())); - } - -} \ No newline at end of file diff --git a/src/tests/model/SubtaskTest.java b/src/tests/model/SubtaskTest.java deleted file mode 100644 index 68fc489..0000000 --- a/src/tests/model/SubtaskTest.java +++ /dev/null @@ -1,19 +0,0 @@ -package tests.model; - -import model.Status; -import model.Subtask; -import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - -public class SubtaskTest { - - @Test - public void testSubtaskCreation() { - Subtask subtask = new Subtask("Test", "Description", Status.NEW, 1); - assertEquals("Test", subtask.getTitle()); - assertEquals("Description", subtask.getDescription()); - assertEquals(Status.NEW, subtask.getStatus()); - assertEquals(1, subtask.getEpicId()); - } - -} \ No newline at end of file diff --git a/src/tests/model/TaskTest.java b/src/tests/model/TaskTest.java deleted file mode 100644 index 1d39ff2..0000000 --- a/src/tests/model/TaskTest.java +++ /dev/null @@ -1,95 +0,0 @@ -package tests.model; - -import model.Status; -import model.Task; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - -class TaskTest { - private Task task; - - @BeforeEach - void setUp() { - task = new Task("Test Task", "Test Description", Status.NEW); - task.setId(1); - } - - @Test - void testConstructorAndGetters() { - assertEquals(1, task.getId()); - assertEquals("Test Task", task.getTitle()); - assertEquals("Test Description", task.getDescription()); - assertEquals(Status.NEW, task.getStatus()); - } - - @Test - void testSetters() { - task.setId(42); - task.setTitle("Updated Title"); - task.setDescription("Updated Description"); - task.setStatus(Status.IN_PROGRESS); - - assertEquals(42, task.getId()); - assertEquals("Updated Title", task.getTitle()); - assertEquals("Updated Description", task.getDescription()); - assertEquals(Status.IN_PROGRESS, task.getStatus()); - } - - @Test - void testEquals_sameValues_shouldBeEqual() { - Task other = new Task("Test Task", "Test Description", Status.NEW); - other.setId(1); - - assertEquals(task, other); - } - - @Test - void testEquals_differentId_shouldNotBeEqual() { - Task other = new Task("Test Task", "Test Description", Status.NEW); - other.setId(99); - - assertNotEquals(task, other); - } - - @Test - void testEquals_differentTitle_shouldNotBeEqual() { - Task other = new Task("Different Title", "Test Description", Status.NEW); - other.setId(1); - - assertNotEquals(task, other); - } - - @Test - void testEquals_differentDescription_shouldNotBeEqual() { - Task other = new Task("Test Task", "Other Description", Status.NEW); - other.setId(1); - - assertNotEquals(task, other); - } - - @Test - void testEquals_differentStatus_shouldNotBeEqual() { - Task other = new Task("Test Task", "Test Description", Status.DONE); - other.setId(1); - - assertNotEquals(task, other); - } - - @Test - void testHashCode_sameValues_shouldBeEqual() { - Task other = new Task("Test Task", "Test Description", Status.NEW); - other.setId(1); - - assertEquals(task.hashCode(), other.hashCode()); - } - - @Test - void testHashCode_differentValues_shouldNotBeEqual() { - Task other = new Task("Other", "Other", Status.DONE); - other.setId(999); - - assertNotEquals(task.hashCode(), other.hashCode()); - } -} \ No newline at end of file From 96ff9b0261d46c80de94a31e13f32e366f0aa7e4 Mon Sep 17 00:00:00 2001 From: n20va <99407852+n20va@users.noreply.github.com> Date: Thu, 10 Jul 2025 22:15:43 +0300 Subject: [PATCH 02/10] Add files via upload --- test/manager/FileBackedTaskManagerTest.java | 105 +++++++++++++++++++ test/manager/InMemoryHistoryManagerTest.java | 60 +++++++++++ test/manager/InMemoryTaskManagerTest.java | 96 +++++++++++++++++ test/model/EpicTest.java | 47 +++++++++ test/model/SubtaskTest.java | 47 +++++++++ test/model/TaskTest.java | 74 +++++++++++++ 6 files changed, 429 insertions(+) create mode 100644 test/manager/FileBackedTaskManagerTest.java create mode 100644 test/manager/InMemoryHistoryManagerTest.java create mode 100644 test/manager/InMemoryTaskManagerTest.java create mode 100644 test/model/EpicTest.java create mode 100644 test/model/SubtaskTest.java create mode 100644 test/model/TaskTest.java diff --git a/test/manager/FileBackedTaskManagerTest.java b/test/manager/FileBackedTaskManagerTest.java new file mode 100644 index 0000000..77dded5 --- /dev/null +++ b/test/manager/FileBackedTaskManagerTest.java @@ -0,0 +1,105 @@ +package test.manager; + +import manager.FileBackedTaskManager; +import manager.TaskManager; +import model.Epic; +import model.Status; +import model.Subtask; +import model.Task; +import org.junit.jupiter.api.*; + +import java.io.File; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class FileBackedTaskManagerTest { + + static File file; + TaskManager manager; + + @BeforeAll + static void beforeAll() { + file = new File("test_data.csv"); + } + + @BeforeEach + void setUp() { + manager = new FileBackedTaskManager(file); + manager.clearTasks(); + manager.clearEpics(); + manager.clearSubtasks(); + } + + @AfterEach + void tearDown() { + if (file.exists()) { + file.delete(); + } + } + + @Test + public void testSaveAndLoad() { + Task task = new Task("Task 1", "Description 1", Status.NEW, + Duration.ofMinutes(30), LocalDateTime.of(2025, 7, 1, 9, 0)); + manager.addTask(task); + + Epic epic = new Epic("Epic 1", "Epic description"); + manager.addEpic(epic); + + Subtask subtask1 = new Subtask("Subtask 1", "Part 1", Status.NEW, + epic.getId(), Duration.ofMinutes(60), LocalDateTime.of(2025, 7, 1, 10, 0)); + Subtask subtask2 = new Subtask("Subtask 2", "Part 2", Status.DONE, + epic.getId(), Duration.ofMinutes(90), LocalDateTime.of(2025, 7, 1, 12, 0)); + manager.addSubtask(subtask1); + manager.addSubtask(subtask2); + + manager.getTaskById(task.getId()); + manager.getEpicById(epic.getId()); + manager.getSubtaskById(subtask1.getId()); + + TaskManager loadedManager = FileBackedTaskManager.loadFromFile(file); + + Task loadedTask = loadedManager.getTaskById(task.getId()); + assertNotNull(loadedTask); + assertEquals(task.getTitle(), loadedTask.getTitle()); + assertEquals(task.getDuration(), loadedTask.getDuration()); + assertEquals(task.getStartTime(), loadedTask.getStartTime()); + + Epic loadedEpic = loadedManager.getEpicById(epic.getId()); + assertNotNull(loadedEpic); + assertEquals(epic.getTitle(), loadedEpic.getTitle()); + + List loadedSubtasks = loadedManager.getSubtasksOfEpic(epic.getId()); + assertEquals(2, loadedSubtasks.size()); + + Subtask loadedSubtask1 = loadedManager.getSubtaskById(subtask1.getId()); + assertEquals(subtask1.getDuration(), loadedSubtask1.getDuration()); + assertEquals(subtask1.getStartTime(), loadedSubtask1.getStartTime()); + + List history = loadedManager.getHistory(); + assertEquals(3, history.size()); + assertEquals(task.getId(), history.get(0).getId()); + assertEquals(epic.getId(), history.get(1).getId()); + assertEquals(subtask1.getId(), history.get(2).getId()); + } + + @Test + public void testLoadFromCorruptedFile() { + try { + java.nio.file.Files.writeString(file.toPath(), "Not a valid CSV content\n"); + } catch (Exception e) { + fail("Не удалось записать тестовый файл"); + } + + TaskManager loadedManager = FileBackedTaskManager.loadFromFile(file); + assertNotNull(loadedManager); + assertTrue(loadedManager.getAllTasks().isEmpty()); + assertTrue(loadedManager.getAllEpics().isEmpty()); + assertTrue(loadedManager.getAllSubtasks().isEmpty()); + assertTrue(loadedManager.getHistory().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..be833bd --- /dev/null +++ b/test/manager/InMemoryHistoryManagerTest.java @@ -0,0 +1,60 @@ +package test.manager; + +import manager.InMemoryHistoryManager; +import model.Task; +import model.Status; +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.*; + +class InMemoryHistoryManagerTest { + private InMemoryHistoryManager historyManager; + + @BeforeEach + void setUp() { + historyManager = new InMemoryHistoryManager(); + } + + @Test + void shouldAddAndReturnHistory() { + Task task = new Task("Test task", "Description", Status.NEW, Duration.ofMinutes(30), LocalDateTime.now()); + task.setId(1); + + historyManager.add(task); + List history = historyManager.getHistory(); + + assertEquals(1, history.size()); + assertEquals(task, history.get(0)); + } + + @Test + void shouldNotAddDuplicates() { + Task task = new Task("Task", "Desc", Status.NEW, Duration.ofMinutes(20), LocalDateTime.now()); + task.setId(1); + historyManager.add(task); + historyManager.add(task); + + assertEquals(1, historyManager.getHistory().size()); + } + + @Test + void shouldRemoveFromHistory() { + Task task1 = new Task("Task 1", "Desc 1", Status.NEW, Duration.ofMinutes(10), LocalDateTime.now()); + task1.setId(1); + Task task2 = new Task("Task 2", "Desc 2", Status.NEW, Duration.ofMinutes(10), LocalDateTime.now()); + task2.setId(2); + + historyManager.add(task1); + historyManager.add(task2); + historyManager.remove(1); + + List history = historyManager.getHistory(); + assertEquals(1, history.size()); + assertEquals(task2, history.get(0)); + } +} diff --git a/test/manager/InMemoryTaskManagerTest.java b/test/manager/InMemoryTaskManagerTest.java new file mode 100644 index 0000000..9668b82 --- /dev/null +++ b/test/manager/InMemoryTaskManagerTest.java @@ -0,0 +1,96 @@ +package test.manager; + +import manager.InMemoryTaskManager; +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.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class InMemoryTaskManagerTest { + + private InMemoryTaskManager manager; + + @BeforeEach + public void setUp() { + manager = new InMemoryTaskManager(); + } + + @Test + public void testAddAndGetTask() { + Task task = new Task("Task 1", "Description task 1", Status.NEW, Duration.ZERO, null); + manager.addTask(task); + + List tasks = manager.getAllTasks(); + assertEquals(1, tasks.size()); + assertEquals(task.getTitle(), tasks.get(0).getTitle()); + } + + @Test + public void testAddAndGetEpic() { + Epic epic = new Epic("Epic 1", "Description epic 1"); + manager.addEpic(epic); + + List epics = manager.getAllEpics(); + assertEquals(1, epics.size()); + assertEquals(epic.getTitle(), epics.get(0).getTitle()); + } + + @Test + public void testAddAndGetSubtask() { + Epic epic = new Epic("Epic 1", "Description epic 1"); + manager.addEpic(epic); + + Subtask subtask = new Subtask("Subtask 1", "Description subtask 1", Status.NEW, epic.getId(), Duration.ZERO, null); + manager.addSubtask(subtask); + + List subtasks = manager.getAllSubtasks(); + assertEquals(1, subtasks.size()); + assertEquals(subtask.getTitle(), subtasks.get(0).getTitle()); + + Epic updatedEpic = manager.getEpicById(epic.getId()); + assertTrue(updatedEpic.getSubtaskIds().contains(subtask.getId())); + } + + @Test + public void testRemoveTask() { + Task task = new Task("Task 1", "Description task 1", Status.NEW, Duration.ZERO, null); + manager.addTask(task); + + manager.removeTaskById(task.getId()); + assertTrue(manager.getAllTasks().isEmpty()); + } + + @Test + public void testRemoveEpicAlsoRemovesSubtasks() { + Epic epic = new Epic("Epic 1", "Description epic 1"); + manager.addEpic(epic); + + Subtask subtask = new Subtask("Subtask 1", "Description subtask 1", Status.NEW, epic.getId(), Duration.ZERO, null); + manager.addSubtask(subtask); + + manager.removeEpicById(epic.getId()); + + assertTrue(manager.getAllEpics().isEmpty()); + + assertTrue(manager.getAllSubtasks().isEmpty()); + } + + @Test + public void testUpdateTask() { + Task task = new Task("Task 1", "Description task 1", Status.NEW, Duration.ZERO, null); + manager.addTask(task); + + task.setStatus(Status.DONE); + manager.updateTask(task); + + Task updated = manager.getTaskById(task.getId()); + assertEquals(Status.DONE, updated.getStatus()); + } +} \ No newline at end of file diff --git a/test/model/EpicTest.java b/test/model/EpicTest.java new file mode 100644 index 0000000..1e861e0 --- /dev/null +++ b/test/model/EpicTest.java @@ -0,0 +1,47 @@ +package test.model; + +import model.Epic; +import model.Status; +import model.Subtask; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.time.Duration; +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.*; + +public class EpicTest { + + private Epic epic; + private Subtask s1; + private Subtask s2; + + @BeforeEach + public void setUp() { + epic = new Epic("Epic Title", "Epic Description"); + } + + @Test + public void shouldReturnNewStatusIfAllSubtasksNew() { + Subtask s1 = new Subtask("Sub1", "Desc1", Status.NEW, epic.getId(), + Duration.ofMinutes(30), LocalDateTime.of(2025, 7, 1, 10, 0)); + Subtask s2 = new Subtask("Sub2", "Desc2", Status.NEW, epic.getId(), + Duration.ofMinutes(60), LocalDateTime.of(2025, 7, 1, 12, 0)); + + epic.addSubtaskId(s1.getEpicId()); + epic.addSubtaskId(s2.getEpicId()); + + assertEquals(Status.NEW, epic.getStatus()); + } + + + + @Test + void epicIsCreatedWithEmptySubtaskList() { + assertNotNull(epic.getSubtaskIds()); + assertTrue(epic.getSubtaskIds().isEmpty()); + } + + +} \ No newline at end of file diff --git a/test/model/SubtaskTest.java b/test/model/SubtaskTest.java new file mode 100644 index 0000000..e4fb140 --- /dev/null +++ b/test/model/SubtaskTest.java @@ -0,0 +1,47 @@ +package test.model; + +import model.Status; +import model.Subtask; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.time.Duration; +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.*; + +class SubtaskTest { + + private Subtask subtask; + + @BeforeEach + void setUp() { + subtask = new Subtask("Subtask 1", "Subtask Description", Status.IN_PROGRESS, 10, Duration.ZERO, null); + subtask.setId(2); + subtask.setDuration(Duration.ofMinutes(45)); + subtask.setStartTime(LocalDateTime.of(2025, 7, 10, 11, 0)); + } + + @Test + void testGettersAndSetters() { + assertEquals(2, subtask.getId()); + assertEquals("Subtask 1", subtask.getTitle()); + assertEquals("Subtask Description", subtask.getDescription()); + assertEquals(Status.IN_PROGRESS, subtask.getStatus()); + assertEquals(10, subtask.getEpicId()); + assertEquals(Duration.ofMinutes(45), subtask.getDuration()); + assertEquals(LocalDateTime.of(2025, 7, 10, 11, 0), subtask.getStartTime()); + } + + @Test + void testGetEndTimeCalculation() { + LocalDateTime expectedEnd = subtask.getStartTime().plus(subtask.getDuration()); + assertEquals(expectedEnd, subtask.getEndTime()); + } + + @Test + void testToStringContainsEpicId() { + String toString = subtask.toString(); + assertTrue(toString.contains("epicId=10")); + } +} \ No newline at end of file diff --git a/test/model/TaskTest.java b/test/model/TaskTest.java new file mode 100644 index 0000000..1f8a449 --- /dev/null +++ b/test/model/TaskTest.java @@ -0,0 +1,74 @@ +package test.model; + +import model.Status; +import model.Task; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.time.Duration; +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.*; + +public class TaskTest { + + private Task task; + + @BeforeEach + public void setUp() { + task = new Task( + "Test Task", + "Description of test task", + Status.NEW, + Duration.ofMinutes(120), + LocalDateTime.of(2025, 7, 10, 9, 0) + ); + } + + @Test + public void shouldCreateTaskWithCorrectFields() { + assertEquals("Test Task", task.getTitle()); + assertEquals("Description of test task", task.getDescription()); + assertEquals(Status.NEW, task.getStatus()); + assertEquals(Duration.ofMinutes(120), task.getDuration()); + assertEquals(LocalDateTime.of(2025, 7, 10, 9, 0), task.getStartTime()); + } + + @Test + public void shouldCalculateEndTimeCorrectly() { + LocalDateTime expectedEndTime = LocalDateTime.of(2025, 7, 10, 11, 0); + assertEquals(expectedEndTime, task.getEndTime()); + } + + @Test + public void shouldUpdateStatus() { + task.setStatus(Status.IN_PROGRESS); + assertEquals(Status.IN_PROGRESS, task.getStatus()); + } + + @Test + public void shouldUpdateStartTimeAndDuration() { + task.setStartTime(LocalDateTime.of(2025, 7, 10, 10, 0)); + task.setDuration(Duration.ofMinutes(30)); + + assertEquals(LocalDateTime.of(2025, 7, 10, 10, 0), task.getStartTime()); + assertEquals(Duration.ofMinutes(30), task.getDuration()); + assertEquals(LocalDateTime.of(2025, 7, 10, 10, 30), task.getEndTime()); + } + + @Test + public void toStringShouldContainAllFields() { + String str = task.toString(); + + assertNotNull(str); + assertFalse(str.isEmpty()); + + assertTrue(str.contains(task.getTitle())); + assertTrue(str.contains(task.getDescription())); + assertTrue(str.contains(task.getStatus().toString())); + + assertTrue(str.contains(String.valueOf(task.getDuration().toMinutes()))); + + assertTrue(str.contains(task.getStartTime().toString())); + } +} \ No newline at end of file From 6143c170e217d72cff983e0a4e9973fc8a0a89db Mon Sep 17 00:00:00 2001 From: n20va <99407852+n20va@users.noreply.github.com> Date: Thu, 10 Jul 2025 22:16:10 +0300 Subject: [PATCH 03/10] Delete src/test directory --- .../manager/FileBackedTaskManagerTest.java | 105 ------------------ .../manager/InMemoryHistoryManagerTest.java | 60 ---------- src/test/manager/InMemoryTaskManagerTest.java | 96 ---------------- src/test/model/EpicTest.java | 47 -------- src/test/model/SubtaskTest.java | 47 -------- src/test/model/TaskTest.java | 74 ------------ 6 files changed, 429 deletions(-) delete mode 100644 src/test/manager/FileBackedTaskManagerTest.java delete mode 100644 src/test/manager/InMemoryHistoryManagerTest.java delete mode 100644 src/test/manager/InMemoryTaskManagerTest.java delete mode 100644 src/test/model/EpicTest.java delete mode 100644 src/test/model/SubtaskTest.java delete mode 100644 src/test/model/TaskTest.java diff --git a/src/test/manager/FileBackedTaskManagerTest.java b/src/test/manager/FileBackedTaskManagerTest.java deleted file mode 100644 index 7b968ff..0000000 --- a/src/test/manager/FileBackedTaskManagerTest.java +++ /dev/null @@ -1,105 +0,0 @@ -package test.manager; - -import manager.FileBackedTaskManager; -import manager.TaskManager; -import model.Epic; -import model.Status; -import model.Subtask; -import model.Task; -import org.junit.jupiter.api.*; - -import java.io.File; -import java.time.Duration; -import java.time.LocalDateTime; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; - -public class FileBackedTaskManagerTest { - - static File file; - TaskManager manager; - - @BeforeAll - static void beforeAll() { - file = new File("test_data.csv"); - } - - @BeforeEach - void setUp() { - manager = new FileBackedTaskManager(file); - manager.clearTasks(); - manager.clearEpics(); - manager.clearSubtasks(); - } - - @AfterEach - void tearDown() { - if (file.exists()) { - file.delete(); - } - } - - @Test - public void testSaveAndLoad() { - Task task = new Task("Task 1", "Description 1", Status.NEW, - Duration.ofMinutes(30), LocalDateTime.of(2025, 7, 1, 9, 0)); - manager.addTask(task); - - Epic epic = new Epic("Epic 1", "Epic description"); - manager.addEpic(epic); - - Subtask subtask1 = new Subtask("Subtask 1", "Part 1", Status.NEW, - epic.getId(), Duration.ofMinutes(60), LocalDateTime.of(2025, 7, 1, 10, 0)); - Subtask subtask2 = new Subtask("Subtask 2", "Part 2", Status.DONE, - epic.getId(), Duration.ofMinutes(90), LocalDateTime.of(2025, 7, 1, 12, 0)); - manager.addSubtask(subtask1); - manager.addSubtask(subtask2); - - manager.getTaskById(task.getId()); - manager.getEpicById(epic.getId()); - manager.getSubtaskById(subtask1.getId()); - - TaskManager loadedManager = FileBackedTaskManager.loadFromFile(file); - - Task loadedTask = loadedManager.getTaskById(task.getId()); - assertNotNull(loadedTask); - assertEquals(task.getTitle(), loadedTask.getTitle()); - assertEquals(task.getDuration(), loadedTask.getDuration()); - assertEquals(task.getStartTime(), loadedTask.getStartTime()); - - Epic loadedEpic = loadedManager.getEpicById(epic.getId()); - assertNotNull(loadedEpic); - assertEquals(epic.getTitle(), loadedEpic.getTitle()); - - List loadedSubtasks = loadedManager.getSubtasksOfEpic(epic.getId()); - assertEquals(2, loadedSubtasks.size()); - - Subtask loadedSubtask1 = loadedManager.getSubtaskById(subtask1.getId()); - assertEquals(subtask1.getDuration(), loadedSubtask1.getDuration()); - assertEquals(subtask1.getStartTime(), loadedSubtask1.getStartTime()); - - List history = loadedManager.getHistory(); - assertEquals(3, history.size()); - assertEquals(task.getId(), history.get(0).getId()); - assertEquals(epic.getId(), history.get(1).getId()); - assertEquals(subtask1.getId(), history.get(2).getId()); - } - - @Test - public void testLoadFromCorruptedFile() { - try { - java.nio.file.Files.writeString(file.toPath(), "Not a valid CSV content\n"); - } catch (Exception e) { - fail("Не удалось записать тестовый файл"); - } - - TaskManager loadedManager = FileBackedTaskManager.loadFromFile(file); - assertNotNull(loadedManager); - assertTrue(loadedManager.getAllTasks().isEmpty()); - assertTrue(loadedManager.getAllEpics().isEmpty()); - assertTrue(loadedManager.getAllSubtasks().isEmpty()); - assertTrue(loadedManager.getHistory().isEmpty()); - } - -} \ No newline at end of file diff --git a/src/test/manager/InMemoryHistoryManagerTest.java b/src/test/manager/InMemoryHistoryManagerTest.java deleted file mode 100644 index b1f7243..0000000 --- a/src/test/manager/InMemoryHistoryManagerTest.java +++ /dev/null @@ -1,60 +0,0 @@ -package test.manager; - -import manager.InMemoryHistoryManager; -import model.Task; -import model.Status; -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.*; - -class InMemoryHistoryManagerTest { - private InMemoryHistoryManager historyManager; - - @BeforeEach - void setUp() { - historyManager = new InMemoryHistoryManager(); - } - - @Test - void shouldAddAndReturnHistory() { - Task task = new Task("Test task", "Description", Status.NEW, Duration.ofMinutes(30), LocalDateTime.now()); - task.setId(1); - - historyManager.add(task); - List history = historyManager.getHistory(); - - assertEquals(1, history.size()); - assertEquals(task, history.get(0)); - } - - @Test - void shouldNotAddDuplicates() { - Task task = new Task("Task", "Desc", Status.NEW, Duration.ofMinutes(20), LocalDateTime.now()); - task.setId(1); - historyManager.add(task); - historyManager.add(task); - - assertEquals(1, historyManager.getHistory().size()); - } - - @Test - void shouldRemoveFromHistory() { - Task task1 = new Task("Task 1", "Desc 1", Status.NEW, Duration.ofMinutes(10), LocalDateTime.now()); - task1.setId(1); - Task task2 = new Task("Task 2", "Desc 2", Status.NEW, Duration.ofMinutes(10), LocalDateTime.now()); - task2.setId(2); - - historyManager.add(task1); - historyManager.add(task2); - historyManager.remove(1); - - List history = historyManager.getHistory(); - assertEquals(1, history.size()); - assertEquals(task2, history.get(0)); - } -} diff --git a/src/test/manager/InMemoryTaskManagerTest.java b/src/test/manager/InMemoryTaskManagerTest.java deleted file mode 100644 index 36b0f48..0000000 --- a/src/test/manager/InMemoryTaskManagerTest.java +++ /dev/null @@ -1,96 +0,0 @@ -package test.manager; - -import manager.InMemoryTaskManager; -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.util.List; - -import static org.junit.jupiter.api.Assertions.*; - -public class InMemoryTaskManagerTest { - - private InMemoryTaskManager manager; - - @BeforeEach - public void setUp() { - manager = new InMemoryTaskManager(); - } - - @Test - public void testAddAndGetTask() { - Task task = new Task("Task 1", "Description task 1", Status.NEW, Duration.ZERO, null); - manager.addTask(task); - - List tasks = manager.getAllTasks(); - assertEquals(1, tasks.size()); - assertEquals(task.getTitle(), tasks.get(0).getTitle()); - } - - @Test - public void testAddAndGetEpic() { - Epic epic = new Epic("Epic 1", "Description epic 1"); - manager.addEpic(epic); - - List epics = manager.getAllEpics(); - assertEquals(1, epics.size()); - assertEquals(epic.getTitle(), epics.get(0).getTitle()); - } - - @Test - public void testAddAndGetSubtask() { - Epic epic = new Epic("Epic 1", "Description epic 1"); - manager.addEpic(epic); - - Subtask subtask = new Subtask("Subtask 1", "Description subtask 1", Status.NEW, epic.getId(), Duration.ZERO, null); - manager.addSubtask(subtask); - - List subtasks = manager.getAllSubtasks(); - assertEquals(1, subtasks.size()); - assertEquals(subtask.getTitle(), subtasks.get(0).getTitle()); - - Epic updatedEpic = manager.getEpicById(epic.getId()); - assertTrue(updatedEpic.getSubtaskIds().contains(subtask.getId())); - } - - @Test - public void testRemoveTask() { - Task task = new Task("Task 1", "Description task 1", Status.NEW, Duration.ZERO, null); - manager.addTask(task); - - manager.removeTaskById(task.getId()); - assertTrue(manager.getAllTasks().isEmpty()); - } - - @Test - public void testRemoveEpicAlsoRemovesSubtasks() { - Epic epic = new Epic("Epic 1", "Description epic 1"); - manager.addEpic(epic); - - Subtask subtask = new Subtask("Subtask 1", "Description subtask 1", Status.NEW, epic.getId(), Duration.ZERO, null); - manager.addSubtask(subtask); - - manager.removeEpicById(epic.getId()); - - assertTrue(manager.getAllEpics().isEmpty()); - - assertTrue(manager.getAllSubtasks().isEmpty()); - } - - @Test - public void testUpdateTask() { - Task task = new Task("Task 1", "Description task 1", Status.NEW, Duration.ZERO, null); - manager.addTask(task); - - task.setStatus(Status.DONE); - manager.updateTask(task); - - Task updated = manager.getTaskById(task.getId()); - assertEquals(Status.DONE, updated.getStatus()); - } -} \ No newline at end of file diff --git a/src/test/model/EpicTest.java b/src/test/model/EpicTest.java deleted file mode 100644 index a851659..0000000 --- a/src/test/model/EpicTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package test.model; - -import model.Epic; -import model.Status; -import model.Subtask; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.time.Duration; -import java.time.LocalDateTime; - -import static org.junit.jupiter.api.Assertions.*; - -public class EpicTest { - - private Epic epic; - private Subtask s1; - private Subtask s2; - - @BeforeEach - public void setUp() { - epic = new Epic("Epic Title", "Epic Description"); - } - - @Test - public void shouldReturnNewStatusIfAllSubtasksNew() { - Subtask s1 = new Subtask("Sub1", "Desc1", Status.NEW, epic.getId(), - Duration.ofMinutes(30), LocalDateTime.of(2025, 7, 1, 10, 0)); - Subtask s2 = new Subtask("Sub2", "Desc2", Status.NEW, epic.getId(), - Duration.ofMinutes(60), LocalDateTime.of(2025, 7, 1, 12, 0)); - - epic.addSubtaskId(s1.getEpicId()); - epic.addSubtaskId(s2.getEpicId()); - - assertEquals(Status.NEW, epic.getStatus()); - } - - - - @Test - void epicIsCreatedWithEmptySubtaskList() { - assertNotNull(epic.getSubtaskIds()); - assertTrue(epic.getSubtaskIds().isEmpty()); - } - - -} \ No newline at end of file diff --git a/src/test/model/SubtaskTest.java b/src/test/model/SubtaskTest.java deleted file mode 100644 index a56aba1..0000000 --- a/src/test/model/SubtaskTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package test.model; - -import model.Status; -import model.Subtask; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.time.Duration; -import java.time.LocalDateTime; - -import static org.junit.jupiter.api.Assertions.*; - -class SubtaskTest { - - private Subtask subtask; - - @BeforeEach - void setUp() { - subtask = new Subtask("Subtask 1", "Subtask Description", Status.IN_PROGRESS, 10, Duration.ZERO, null); - subtask.setId(2); - subtask.setDuration(Duration.ofMinutes(45)); - subtask.setStartTime(LocalDateTime.of(2025, 7, 10, 11, 0)); - } - - @Test - void testGettersAndSetters() { - assertEquals(2, subtask.getId()); - assertEquals("Subtask 1", subtask.getTitle()); - assertEquals("Subtask Description", subtask.getDescription()); - assertEquals(Status.IN_PROGRESS, subtask.getStatus()); - assertEquals(10, subtask.getEpicId()); - assertEquals(Duration.ofMinutes(45), subtask.getDuration()); - assertEquals(LocalDateTime.of(2025, 7, 10, 11, 0), subtask.getStartTime()); - } - - @Test - void testGetEndTimeCalculation() { - LocalDateTime expectedEnd = subtask.getStartTime().plus(subtask.getDuration()); - assertEquals(expectedEnd, subtask.getEndTime()); - } - - @Test - void testToStringContainsEpicId() { - String toString = subtask.toString(); - assertTrue(toString.contains("epicId=10")); - } -} \ No newline at end of file diff --git a/src/test/model/TaskTest.java b/src/test/model/TaskTest.java deleted file mode 100644 index 4013ac6..0000000 --- a/src/test/model/TaskTest.java +++ /dev/null @@ -1,74 +0,0 @@ -package test.model; - -import model.Status; -import model.Task; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.time.Duration; -import java.time.LocalDateTime; - -import static org.junit.jupiter.api.Assertions.*; - -public class TaskTest { - - private Task task; - - @BeforeEach - public void setUp() { - task = new Task( - "Test Task", - "Description of test task", - Status.NEW, - Duration.ofMinutes(120), - LocalDateTime.of(2025, 7, 10, 9, 0) - ); - } - - @Test - public void shouldCreateTaskWithCorrectFields() { - assertEquals("Test Task", task.getTitle()); - assertEquals("Description of test task", task.getDescription()); - assertEquals(Status.NEW, task.getStatus()); - assertEquals(Duration.ofMinutes(120), task.getDuration()); - assertEquals(LocalDateTime.of(2025, 7, 10, 9, 0), task.getStartTime()); - } - - @Test - public void shouldCalculateEndTimeCorrectly() { - LocalDateTime expectedEndTime = LocalDateTime.of(2025, 7, 10, 11, 0); - assertEquals(expectedEndTime, task.getEndTime()); - } - - @Test - public void shouldUpdateStatus() { - task.setStatus(Status.IN_PROGRESS); - assertEquals(Status.IN_PROGRESS, task.getStatus()); - } - - @Test - public void shouldUpdateStartTimeAndDuration() { - task.setStartTime(LocalDateTime.of(2025, 7, 10, 10, 0)); - task.setDuration(Duration.ofMinutes(30)); - - assertEquals(LocalDateTime.of(2025, 7, 10, 10, 0), task.getStartTime()); - assertEquals(Duration.ofMinutes(30), task.getDuration()); - assertEquals(LocalDateTime.of(2025, 7, 10, 10, 30), task.getEndTime()); - } - - @Test - public void toStringShouldContainAllFields() { - String str = task.toString(); - - assertNotNull(str); - assertFalse(str.isEmpty()); - - assertTrue(str.contains(task.getTitle())); - assertTrue(str.contains(task.getDescription())); - assertTrue(str.contains(task.getStatus().toString())); - - assertTrue(str.contains(String.valueOf(task.getDuration().toMinutes()))); - - assertTrue(str.contains(task.getStartTime().toString())); - } -} \ No newline at end of file From 65dd7f13fb975b1d2eb33b1988862e3fbf4164f1 Mon Sep 17 00:00:00 2001 From: n20va <99407852+n20va@users.noreply.github.com> Date: Thu, 10 Jul 2025 22:23:08 +0300 Subject: [PATCH 04/10] Update Main.java --- src/Main.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Main.java b/src/Main.java index 4760f4f..1afa596 100644 --- a/src/Main.java +++ b/src/Main.java @@ -5,7 +5,6 @@ import java.io.File; import java.time.Duration; import java.time.LocalDateTime; -import java.util.List; public class Main { public static void main(String[] args) { @@ -51,4 +50,4 @@ public static void main(String[] args) { } } -} \ No newline at end of file +} From 3bf4dfe5fb2c2a0903d8c6813f957e6189524e7d Mon Sep 17 00:00:00 2001 From: n20va <99407852+n20va@users.noreply.github.com> Date: Sun, 13 Jul 2025 09:53:39 +0300 Subject: [PATCH 05/10] Update Epic.java --- src/model/Epic.java | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/model/Epic.java b/src/model/Epic.java index 413dc68..cd578ea 100644 --- a/src/model/Epic.java +++ b/src/model/Epic.java @@ -4,9 +4,11 @@ import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; +import java.util.Objects; public class Epic extends Task { - private List subtaskIds = new ArrayList<>(); + private final List subtaskIds = new ArrayList<>(); + private LocalDateTime endTime; public Epic(String title, String description) { super(title, description, Status.NEW, Duration.ZERO, null); @@ -26,18 +28,25 @@ public void removeSubtaskId(int id) { } @Override - public Duration getDuration() { - return super.getDuration(); + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; } @Override - public LocalDateTime getStartTime() { - return super.getStartTime(); + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Epic epic)) return false; + if (!super.equals(o)) return false; + return Objects.equals(subtaskIds, epic.subtaskIds); } @Override - public LocalDateTime getEndTime() { - return super.getEndTime(); + public int hashCode() { + return Objects.hash(super.hashCode(), subtaskIds); } @Override @@ -47,11 +56,10 @@ public String toString() { ", title='" + getTitle() + '\'' + ", description='" + getDescription() + '\'' + ", status=" + getStatus() + - ", duration=" + (getDuration() != null ? getDuration().toMinutes() : "null") + ", startTime=" + getStartTime() + + ", duration=" + getDuration() + + ", endTime=" + getEndTime() + ", subtaskIds=" + subtaskIds + '}'; } - - -} \ No newline at end of file +} From f4b7666b5b86b36d50c86471c55b963a85a7fcfa Mon Sep 17 00:00:00 2001 From: n20va <99407852+n20va@users.noreply.github.com> Date: Sun, 13 Jul 2025 09:54:49 +0300 Subject: [PATCH 06/10] Update InMemoryTaskManager.java --- src/manager/InMemoryTaskManager.java | 262 +++++++++------------------ 1 file changed, 86 insertions(+), 176 deletions(-) diff --git a/src/manager/InMemoryTaskManager.java b/src/manager/InMemoryTaskManager.java index 624f846..e51eeac 100644 --- a/src/manager/InMemoryTaskManager.java +++ b/src/manager/InMemoryTaskManager.java @@ -8,62 +8,43 @@ import java.time.Duration; import java.time.LocalDateTime; import java.util.*; +import java.util.stream.Collectors; public class InMemoryTaskManager implements TaskManager { - + protected int idCounter = 1; protected final Map tasks = new HashMap<>(); protected final Map epics = new HashMap<>(); protected final Map subtasks = new HashMap<>(); + protected final HistoryManager historyManager = Managers.getDefaultHistory(); protected final Set prioritizedTasks = new TreeSet<>(Comparator .comparing(Task::getStartTime, Comparator.nullsLast(LocalDateTime::compareTo)) .thenComparingInt(Task::getId)); - protected final List history = new ArrayList<>(); - protected final HistoryManager historyManager = Managers.getDefaultHistory(); - protected int nextId = 1; + protected int generateId() { + return idCounter++; + } @Override public void addTask(Task task) { - if (task == null) return; - if (task.getId() == 0) { - task.setId(nextId++); - } - if (checkTimeIntersection(task)) { - throw new IllegalArgumentException("Task time intersects with existing task"); - } + task.setId(generateId()); tasks.put(task.getId(), task); prioritizedTasks.add(task); } @Override public void addEpic(Epic epic) { - if (epic == null) return; - if (epic.getId() == 0) { - epic.setId(nextId++); - } + epic.setId(generateId()); epics.put(epic.getId(), epic); - updateEpicTimeAndDuration(epic); } @Override public void addSubtask(Subtask subtask) { - if (subtask == null) return; - if (!epics.containsKey(subtask.getEpicId())) { - throw new IllegalArgumentException("Epic does not exist for subtask"); - } - if (subtask.getId() == 0) { - subtask.setId(nextId++); - } - if (checkTimeIntersection(subtask)) { - throw new IllegalArgumentException("Subtask time intersects with existing task"); - } + subtask.setId(generateId()); subtasks.put(subtask.getId(), subtask); - prioritizedTasks.add(subtask); - Epic epic = epics.get(subtask.getEpicId()); epic.addSubtaskId(subtask.getId()); - updateEpicStatus(epic); - updateEpicTimeAndDuration(epic); + updateEpicFields(epic); + prioritizedTasks.add(subtask); } @Override @@ -84,67 +65,55 @@ public List getAllSubtasks() { @Override public Task getTaskById(int id) { Task task = tasks.get(id); - if (task != null) addToHistory(task); + if (task != null) historyManager.add(task); return task; } @Override public Epic getEpicById(int id) { Epic epic = epics.get(id); - if (epic != null) addToHistory(epic); + if (epic != null) historyManager.add(epic); return epic; } @Override public Subtask getSubtaskById(int id) { Subtask subtask = subtasks.get(id); - if (subtask != null) addToHistory(subtask); + if (subtask != null) historyManager.add(subtask); return subtask; } @Override public void updateTask(Task task) { - if (task == null || !tasks.containsKey(task.getId())) return; - if (checkTimeIntersection(task, task.getId())) { - throw new IllegalArgumentException("Task time intersects with existing task"); + if (tasks.containsKey(task.getId())) { + prioritizedTasks.remove(tasks.get(task.getId())); + tasks.put(task.getId(), task); + prioritizedTasks.add(task); } - prioritizedTasks.remove(tasks.get(task.getId())); - tasks.put(task.getId(), task); - prioritizedTasks.add(task); } @Override public void updateEpic(Epic epic) { - if (epic == null || !epics.containsKey(epic.getId())) return; - epics.put(epic.getId(), epic); - updateEpicTimeAndDuration(epic); + if (epics.containsKey(epic.getId())) { + epics.put(epic.getId(), epic); + updateEpicFields(epic); + } } - @Override public void updateSubtask(Subtask subtask) { - if (subtask == null || !subtasks.containsKey(subtask.getId())) return; - if (checkTimeIntersection(subtask, subtask.getId())) { - throw new IllegalArgumentException("Subtask time intersects with existing task"); + if (subtasks.containsKey(subtask.getId())) { + prioritizedTasks.remove(subtasks.get(subtask.getId())); + subtasks.put(subtask.getId(), subtask); + prioritizedTasks.add(subtask); + updateEpicFields(epics.get(subtask.getEpicId())); } - prioritizedTasks.remove(subtasks.get(subtask.getId())); - subtasks.put(subtask.getId(), subtask); - prioritizedTasks.add(subtask); - - Epic epic = epics.get(subtask.getEpicId()); - updateEpicStatus(epic); - updateEpicTimeAndDuration(epic); } @Override public void removeTaskById(int id) { - - Task task = tasks.remove(id); - if (task != null) { - prioritizedTasks.remove(task); - removeFromHistory(task); - } - + prioritizedTasks.remove(tasks.remove(id)); + historyManager.remove(id); } @Override @@ -152,31 +121,23 @@ public void removeEpicById(int id) { Epic epic = epics.remove(id); if (epic != null) { for (int subId : epic.getSubtaskIds()) { - - Subtask subtask = subtasks.remove(subId); - if (subtask != null) { - prioritizedTasks.remove(subtask); - removeFromHistory(subtask); - } + subtasks.remove(subId); + prioritizedTasks.removeIf(t -> t.getId() == subId); + historyManager.remove(subId); } - removeFromHistory(epic); - } + historyManager.remove(id); } @Override public void removeSubtaskById(int id) { Subtask subtask = subtasks.remove(id); if (subtask != null) { - prioritizedTasks.remove(subtask); Epic epic = epics.get(subtask.getEpicId()); - if (epic != null) { - epic.removeSubtaskId(id); - updateEpicStatus(epic); - updateEpicTimeAndDuration(epic); - } - removeFromHistory(subtask); - + epic.removeSubtaskId(id); + updateEpicFields(epic); + prioritizedTasks.remove(subtask); + historyManager.remove(id); } } @@ -184,151 +145,100 @@ public void removeSubtaskById(int id) { public void clearTasks() { for (Task task : tasks.values()) { prioritizedTasks.remove(task); - + historyManager.remove(task.getId()); } tasks.clear(); } @Override public void clearEpics() { - for (Epic epic : epics.values()) { for (int subId : epic.getSubtaskIds()) { - Subtask subtask = subtasks.remove(subId); - if (subtask != null) { - prioritizedTasks.remove(subtask); - } + historyManager.remove(subId); + prioritizedTasks.removeIf(t -> t.getId() == subId); } - removeFromHistory(epic); - + historyManager.remove(epic.getId()); } epics.clear(); + subtasks.clear(); } @Override public void clearSubtasks() { - for (Subtask subtask : subtasks.values()) { + Epic epic = epics.get(subtask.getEpicId()); + epic.removeSubtaskId(subtask.getId()); + updateEpicFields(epic); prioritizedTasks.remove(subtask); - + historyManager.remove(subtask.getId()); } subtasks.clear(); - for (Epic epic : epics.values()) { - epic.getSubtaskIds().clear(); - updateEpicStatus(epic); - updateEpicTimeAndDuration(epic); - } } @Override public List getSubtasksOfEpic(int epicId) { Epic epic = epics.get(epicId); - if (epic == null) return Collections.emptyList(); - List list = new ArrayList<>(); - for (int id : epic.getSubtaskIds()) { - Subtask subtask = subtasks.get(id); - if (subtask != null) { - list.add(subtask); - } - } - return list; - } - - @Override - public List getHistory() { - return new ArrayList<>(history); + if (epic == null) return List.of(); + return epic.getSubtaskIds().stream() + .map(subtasks::get) + .collect(Collectors.toList()); } - @Override - public List getPrioritizedTasks() { - return new ArrayList<>(prioritizedTasks); - } - - private boolean checkTimeIntersection(Task newTask) { - return checkTimeIntersection(newTask, -1); - } - - private boolean checkTimeIntersection(Task newTask, int ignoreId) { - if (newTask.getStartTime() == null || newTask.getDuration() == null) { - return false; - } - LocalDateTime newStart = newTask.getStartTime(); - LocalDateTime newEnd = newTask.getEndTime(); - - for (Task task : prioritizedTasks) { - if (task.getId() == ignoreId) continue; - if (task.getStartTime() == null || task.getDuration() == null) continue; - LocalDateTime start = task.getStartTime(); - LocalDateTime end = task.getEndTime(); - - boolean intersect = newStart.isBefore(end) && newEnd.isAfter(start); - if (intersect) { - return true; - } - } - return false; - } - - private void updateEpicStatus(Epic epic) { + private void updateEpicFields(Epic epic) { List subtasksOfEpic = getSubtasksOfEpic(epic.getId()); if (subtasksOfEpic.isEmpty()) { epic.setStatus(Status.NEW); - return; - } - - boolean allNew = subtasksOfEpic.stream().allMatch(s -> s.getStatus() == Status.NEW); - boolean allDone = subtasksOfEpic.stream().allMatch(s -> s.getStatus() == Status.DONE); - - if (allNew) { - epic.setStatus(Status.NEW); - } else if (allDone) { - epic.setStatus(Status.DONE); - } else { - epic.setStatus(Status.IN_PROGRESS); - } - } - - private void updateEpicTimeAndDuration(Epic epic) { - List subtasksOfEpic = getSubtasksOfEpic(epic.getId()); - - if (subtasksOfEpic.isEmpty()) { epic.setDuration(Duration.ZERO); epic.setStartTime(null); + epic.setEndTime(null); return; } - Duration totalDuration = Duration.ZERO; + boolean allNew = true; + boolean allDone = true; LocalDateTime earliestStart = null; LocalDateTime latestEnd = null; + Duration totalDuration = Duration.ZERO; - for (Subtask sub : subtasksOfEpic) { - if (sub.getDuration() != null) { - totalDuration = totalDuration.plus(sub.getDuration()); - } - if (sub.getStartTime() != null) { - if (earliestStart == null || sub.getStartTime().isBefore(earliestStart)) { - earliestStart = sub.getStartTime(); + for (Subtask s : subtasksOfEpic) { + if (s.getStatus() != Status.NEW) allNew = false; + if (s.getStatus() != Status.DONE) allDone = false; + + if (s.getStartTime() != null) { + if (earliestStart == null || s.getStartTime().isBefore(earliestStart)) { + earliestStart = s.getStartTime(); } - LocalDateTime subEnd = sub.getEndTime(); - if (subEnd != null && (latestEnd == null || subEnd.isAfter(latestEnd))) { - latestEnd = subEnd; + LocalDateTime end = s.getEndTime(); + if (latestEnd == null || (end != null && end.isAfter(latestEnd))) { + latestEnd = end; } } + + if (s.getDuration() != null) { + totalDuration = totalDuration.plus(s.getDuration()); + } + } + + if (allNew) { + epic.setStatus(Status.NEW); + } else if (allDone) { + epic.setStatus(Status.DONE); + } else { + epic.setStatus(Status.IN_PROGRESS); } - epic.setDuration(totalDuration); epic.setStartTime(earliestStart); + epic.setEndTime(latestEnd); + epic.setDuration(totalDuration); } - private void addToHistory(Task task) { - history.remove(task); - history.add(task); - if (history.size() > 10) { - history.remove(0); - } + @Override + public List getHistory() { + return historyManager.getHistory(); } - private void removeFromHistory(Task task) { - history.remove(task); + @Override + public List getPrioritizedTasks() { + return new ArrayList<>(prioritizedTasks); } -} \ No newline at end of file +} From 878549cea964971f903768956a616d44c4df6966 Mon Sep 17 00:00:00 2001 From: n20va <99407852+n20va@users.noreply.github.com> Date: Sun, 13 Jul 2025 19:55:18 +0300 Subject: [PATCH 07/10] Update Main.java --- src/Main.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Main.java b/src/Main.java index 1afa596..249c002 100644 --- a/src/Main.java +++ b/src/Main.java @@ -12,9 +12,9 @@ public static void main(String[] args) { TaskManager manager = new FileBackedTaskManager(file); Task task1 = new Task("Task 1", "Simple task", - Status.NEW, Duration.ofMinutes(30), LocalDateTime.of(2025, 7, 1, 10, 0)); + Status.NEW, Duration.ofMinutes(30), LocalDateTime.of(2025, 7, 1, 8, 0)); Task task2 = new Task("Task 2", "Another task", - Status.NEW, Duration.ofMinutes(45), LocalDateTime.of(2025, 7, 1, 11, 0)); + Status.NEW, Duration.ofMinutes(45), LocalDateTime.of(2025, 7, 1, 8, 45)); manager.addTask(task1); manager.addTask(task2); @@ -22,9 +22,9 @@ public static void main(String[] args) { manager.addEpic(epic); Subtask subtask1 = new Subtask("Subtask 1", "Part 1", - Status.NEW, epic.getId(), Duration.ofMinutes(60), LocalDateTime.of(2025, 7, 1, 9, 0)); + Status.NEW, epic.getId(), Duration.ofMinutes(60), LocalDateTime.of(2025, 7, 1, 10, 0)); Subtask subtask2 = new Subtask("Subtask 2", "Part 2", - Status.DONE, epic.getId(), Duration.ofMinutes(90), LocalDateTime.of(2025, 7, 1, 13, 0)); + Status.DONE, epic.getId(), Duration.ofMinutes(90), LocalDateTime.of(2025, 7, 1, 11, 30)); manager.addSubtask(subtask1); manager.addSubtask(subtask2); @@ -47,7 +47,6 @@ public static void main(String[] args) { System.out.println("\n=== Loaded Subtasks ==="); for (Subtask s : loadedManager.getAllSubtasks()) { System.out.println(s); - } } } From c2399878451a8219381f6193ceaf673f9bf3c38e Mon Sep 17 00:00:00 2001 From: n20va <99407852+n20va@users.noreply.github.com> Date: Sun, 13 Jul 2025 19:55:42 +0300 Subject: [PATCH 08/10] Update InMemoryTaskManager.java --- src/manager/InMemoryTaskManager.java | 256 +++++++++++++++------------ 1 file changed, 144 insertions(+), 112 deletions(-) diff --git a/src/manager/InMemoryTaskManager.java b/src/manager/InMemoryTaskManager.java index e51eeac..b38f5df 100644 --- a/src/manager/InMemoryTaskManager.java +++ b/src/manager/InMemoryTaskManager.java @@ -1,65 +1,85 @@ package manager; -import model.Epic; -import model.Status; -import model.Subtask; -import model.Task; - +import model.*; import java.time.Duration; import java.time.LocalDateTime; import java.util.*; -import java.util.stream.Collectors; public class InMemoryTaskManager implements TaskManager { - protected int idCounter = 1; protected final Map tasks = new HashMap<>(); - protected final Map epics = new HashMap<>(); protected final Map subtasks = new HashMap<>(); + protected final Map epics = new HashMap<>(); protected final HistoryManager historyManager = Managers.getDefaultHistory(); + protected int nextId = 1; protected final Set prioritizedTasks = new TreeSet<>(Comparator .comparing(Task::getStartTime, Comparator.nullsLast(LocalDateTime::compareTo)) .thenComparingInt(Task::getId)); protected int generateId() { - return idCounter++; + return nextId++; + } + + private boolean checkTimeIntersection(Task task) { + if (task.getStartTime() == null || task.getEndTime() == null) { + return false; + } + for (Task t : prioritizedTasks) { + if (t.getId() == task.getId() || t.getStartTime() == null || t.getEndTime() == null) continue; + if (!(task.getEndTime().isBefore(t.getStartTime()) || task.getStartTime().isAfter(t.getEndTime()))) { + return true; + } + } + return false; } @Override - public void addTask(Task task) { - task.setId(generateId()); - tasks.put(task.getId(), task); - prioritizedTasks.add(task); + public List getAllTasks() { + return new ArrayList<>(tasks.values()); } @Override - public void addEpic(Epic epic) { - epic.setId(generateId()); - epics.put(epic.getId(), epic); + public List getAllSubtasks() { + return new ArrayList<>(subtasks.values()); } @Override - public void addSubtask(Subtask subtask) { - subtask.setId(generateId()); - subtasks.put(subtask.getId(), subtask); - Epic epic = epics.get(subtask.getEpicId()); - epic.addSubtaskId(subtask.getId()); - updateEpicFields(epic); - prioritizedTasks.add(subtask); + public List getAllEpics() { + return new ArrayList<>(epics.values()); } @Override - public List getAllTasks() { - return new ArrayList<>(tasks.values()); + public void clearTasks() { + for (Task task : tasks.values()) { + prioritizedTasks.remove(task); + historyManager.remove(task.getId()); + } + tasks.clear(); } @Override - public List getAllEpics() { - return new ArrayList<>(epics.values()); + public void clearSubtasks() { + for (Subtask subtask : subtasks.values()) { + prioritizedTasks.remove(subtask); + historyManager.remove(subtask.getId()); + } + subtasks.clear(); + for (Epic epic : epics.values()) { + epic.getSubtaskIds().clear(); + updateEpicFields(epic); + } } @Override - public List getAllSubtasks() { - return new ArrayList<>(subtasks.values()); + public void clearEpics() { + for (Epic epic : epics.values()) { + historyManager.remove(epic.getId()); + } + for (Subtask subtask : subtasks.values()) { + prioritizedTasks.remove(subtask); + historyManager.remove(subtask.getId()); + } + epics.clear(); + subtasks.clear(); } @Override @@ -69,6 +89,13 @@ public Task getTaskById(int id) { return task; } + @Override + public Subtask getSubtaskById(int id) { + Subtask subtask = subtasks.get(id); + if (subtask != null) historyManager.add(subtask); + return subtask; + } + @Override public Epic getEpicById(int id) { Epic epic = epics.get(id); @@ -77,114 +104,121 @@ public Epic getEpicById(int id) { } @Override - public Subtask getSubtaskById(int id) { - Subtask subtask = subtasks.get(id); - if (subtask != null) historyManager.add(subtask); - return subtask; + public void addTask(Task task) { + task.setId(generateId()); + if (checkTimeIntersection(task)) { + throw new IllegalArgumentException("Task time overlaps with another task"); + } + tasks.put(task.getId(), task); + prioritizedTasks.add(task); } @Override - public void updateTask(Task task) { - if (tasks.containsKey(task.getId())) { - prioritizedTasks.remove(tasks.get(task.getId())); - tasks.put(task.getId(), task); - prioritizedTasks.add(task); + public void addEpic(Epic epic) { + epic.setId(generateId()); + epics.put(epic.getId(), epic); + } + + @Override + public void addSubtask(Subtask subtask) { + if (!epics.containsKey(subtask.getEpicId())) { + throw new IllegalArgumentException("Epic not found"); } + subtask.setId(generateId()); + if (checkTimeIntersection(subtask)) { + throw new IllegalArgumentException("Subtask time overlaps with another task"); + } + subtasks.put(subtask.getId(), subtask); + prioritizedTasks.add(subtask); + Epic epic = epics.get(subtask.getEpicId()); + epic.addSubtaskId(subtask.getId()); + updateEpicFields(epic); } @Override - public void updateEpic(Epic epic) { - if (epics.containsKey(epic.getId())) { - epics.put(epic.getId(), epic); - updateEpicFields(epic); + public void updateTask(Task task) { + if (!tasks.containsKey(task.getId())) return; + if (checkTimeIntersection(task)) { + throw new IllegalArgumentException("Task time overlaps with another task"); } + prioritizedTasks.remove(tasks.get(task.getId())); + tasks.put(task.getId(), task); + prioritizedTasks.add(task); } @Override public void updateSubtask(Subtask subtask) { - if (subtasks.containsKey(subtask.getId())) { - prioritizedTasks.remove(subtasks.get(subtask.getId())); - subtasks.put(subtask.getId(), subtask); - prioritizedTasks.add(subtask); - updateEpicFields(epics.get(subtask.getEpicId())); + if (!subtasks.containsKey(subtask.getId())) return; + if (checkTimeIntersection(subtask)) { + throw new IllegalArgumentException("Subtask time overlaps with another task"); } + prioritizedTasks.remove(subtasks.get(subtask.getId())); + subtasks.put(subtask.getId(), subtask); + prioritizedTasks.add(subtask); + updateEpicFields(epics.get(subtask.getEpicId())); } @Override - public void removeTaskById(int id) { - prioritizedTasks.remove(tasks.remove(id)); - historyManager.remove(id); + public void updateEpic(Epic epic) { + int id = epic.getId(); + Epic saved = epics.get(id); + if (saved == null) return; + saved.setTitle(epic.getTitle()); + saved.setDescription(epic.getDescription()); } @Override - public void removeEpicById(int id) { - Epic epic = epics.remove(id); - if (epic != null) { - for (int subId : epic.getSubtaskIds()) { - subtasks.remove(subId); - prioritizedTasks.removeIf(t -> t.getId() == subId); - historyManager.remove(subId); - } + public void removeTaskById(int id) { + Task task = tasks.remove(id); + if (task != null) { + prioritizedTasks.remove(task); + historyManager.remove(id); } - historyManager.remove(id); } @Override public void removeSubtaskById(int id) { Subtask subtask = subtasks.remove(id); if (subtask != null) { - Epic epic = epics.get(subtask.getEpicId()); - epic.removeSubtaskId(id); - updateEpicFields(epic); prioritizedTasks.remove(subtask); + Epic epic = epics.get(subtask.getEpicId()); + if (epic != null) { + epic.removeSubtaskId(id); + updateEpicFields(epic); + } historyManager.remove(id); } } @Override - public void clearTasks() { - for (Task task : tasks.values()) { - prioritizedTasks.remove(task); - historyManager.remove(task.getId()); - } - tasks.clear(); - } - - @Override - public void clearEpics() { - for (Epic epic : epics.values()) { - for (int subId : epic.getSubtaskIds()) { - historyManager.remove(subId); - prioritizedTasks.removeIf(t -> t.getId() == subId); + public void removeEpicById(int id) { + Epic epic = epics.remove(id); + if (epic != null) { + for (int subtaskId : epic.getSubtaskIds()) { + Subtask subtask = subtasks.remove(subtaskId); + if (subtask != null) { + prioritizedTasks.remove(subtask); + historyManager.remove(subtaskId); + } } - historyManager.remove(epic.getId()); - } - epics.clear(); - subtasks.clear(); - } - - @Override - public void clearSubtasks() { - for (Subtask subtask : subtasks.values()) { - Epic epic = epics.get(subtask.getEpicId()); - epic.removeSubtaskId(subtask.getId()); - updateEpicFields(epic); - prioritizedTasks.remove(subtask); - historyManager.remove(subtask.getId()); + historyManager.remove(id); } - subtasks.clear(); } @Override public List getSubtasksOfEpic(int epicId) { - Epic epic = epics.get(epicId); - if (epic == null) return List.of(); - return epic.getSubtaskIds().stream() - .map(subtasks::get) - .collect(Collectors.toList()); + if (!epics.containsKey(epicId)) return Collections.emptyList(); + List result = new ArrayList<>(); + for (int subtaskId : epics.get(epicId).getSubtaskIds()) { + Subtask subtask = subtasks.get(subtaskId); + if (subtask != null) { + result.add(subtask); + } + } + return result; } - private void updateEpicFields(Epic epic) { + protected void updateEpicFields(Epic epic) { List subtasksOfEpic = getSubtasksOfEpic(epic.getId()); if (subtasksOfEpic.isEmpty()) { epic.setStatus(Status.NEW); @@ -196,27 +230,25 @@ private void updateEpicFields(Epic epic) { boolean allNew = true; boolean allDone = true; + Duration totalDuration = Duration.ZERO; LocalDateTime earliestStart = null; LocalDateTime latestEnd = null; - Duration totalDuration = Duration.ZERO; - for (Subtask s : subtasksOfEpic) { - if (s.getStatus() != Status.NEW) allNew = false; - if (s.getStatus() != Status.DONE) allDone = false; + for (Subtask subtask : subtasksOfEpic) { + Status status = subtask.getStatus(); + if (status != Status.NEW) allNew = false; + if (status != Status.DONE) allDone = false; - if (s.getStartTime() != null) { - if (earliestStart == null || s.getStartTime().isBefore(earliestStart)) { - earliestStart = s.getStartTime(); + if (subtask.getStartTime() != null) { + if (earliestStart == null || subtask.getStartTime().isBefore(earliestStart)) { + earliestStart = subtask.getStartTime(); } - LocalDateTime end = s.getEndTime(); - if (latestEnd == null || (end != null && end.isAfter(latestEnd))) { - latestEnd = end; + LocalDateTime subtaskEnd = subtask.getEndTime(); + if (latestEnd == null || subtaskEnd.isAfter(latestEnd)) { + latestEnd = subtaskEnd; } } - - if (s.getDuration() != null) { - totalDuration = totalDuration.plus(s.getDuration()); - } + totalDuration = totalDuration.plus(subtask.getDuration()); } if (allNew) { @@ -227,9 +259,9 @@ private void updateEpicFields(Epic epic) { epic.setStatus(Status.IN_PROGRESS); } + epic.setDuration(totalDuration); epic.setStartTime(earliestStart); epic.setEndTime(latestEnd); - epic.setDuration(totalDuration); } @Override From 8a0ede84459c6ed8265eb54330ca447274b01342 Mon Sep 17 00:00:00 2001 From: n20va <99407852+n20va@users.noreply.github.com> Date: Sun, 13 Jul 2025 19:57:55 +0300 Subject: [PATCH 09/10] Update Main.java --- src/Main.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Main.java b/src/Main.java index 249c002..f122993 100644 --- a/src/Main.java +++ b/src/Main.java @@ -12,9 +12,9 @@ public static void main(String[] args) { TaskManager manager = new FileBackedTaskManager(file); Task task1 = new Task("Task 1", "Simple task", - Status.NEW, Duration.ofMinutes(30), LocalDateTime.of(2025, 7, 1, 8, 0)); + Status.NEW, Duration.ofMinutes(30), LocalDateTime.of(2025, 7, 1, 8, 0)); Task task2 = new Task("Task 2", "Another task", - Status.NEW, Duration.ofMinutes(45), LocalDateTime.of(2025, 7, 1, 8, 45)); + Status.NEW, Duration.ofMinutes(45), LocalDateTime.of(2025, 7, 1, 8, 45)); manager.addTask(task1); manager.addTask(task2); @@ -24,7 +24,7 @@ public static void main(String[] args) { Subtask subtask1 = new Subtask("Subtask 1", "Part 1", Status.NEW, epic.getId(), Duration.ofMinutes(60), LocalDateTime.of(2025, 7, 1, 10, 0)); Subtask subtask2 = new Subtask("Subtask 2", "Part 2", - Status.DONE, epic.getId(), Duration.ofMinutes(90), LocalDateTime.of(2025, 7, 1, 11, 30)); + Status.DONE, epic.getId(), Duration.ofMinutes(90), LocalDateTime.of(2025, 7, 1, 11, 30)); manager.addSubtask(subtask1); manager.addSubtask(subtask2); From 051f56f54858b7ed1c99ffdcde4428a4d55ea2a4 Mon Sep 17 00:00:00 2001 From: n20va <99407852+n20va@users.noreply.github.com> Date: Wed, 16 Jul 2025 11:13:37 +0300 Subject: [PATCH 10/10] Update InMemoryTaskManager.java --- src/manager/InMemoryTaskManager.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/manager/InMemoryTaskManager.java b/src/manager/InMemoryTaskManager.java index b38f5df..f1d4c3d 100644 --- a/src/manager/InMemoryTaskManager.java +++ b/src/manager/InMemoryTaskManager.java @@ -105,10 +105,10 @@ public Epic getEpicById(int id) { @Override public void addTask(Task task) { - task.setId(generateId()); if (checkTimeIntersection(task)) { throw new IllegalArgumentException("Task time overlaps with another task"); } + task.setId(generateId()); tasks.put(task.getId(), task); prioritizedTasks.add(task); } @@ -124,10 +124,10 @@ public void addSubtask(Subtask subtask) { if (!epics.containsKey(subtask.getEpicId())) { throw new IllegalArgumentException("Epic not found"); } - subtask.setId(generateId()); if (checkTimeIntersection(subtask)) { throw new IllegalArgumentException("Subtask time overlaps with another task"); } + subtask.setId(generateId()); subtasks.put(subtask.getId(), subtask); prioritizedTasks.add(subtask); Epic epic = epics.get(subtask.getEpicId()); @@ -149,10 +149,16 @@ public void updateTask(Task task) { @Override public void updateSubtask(Subtask subtask) { if (!subtasks.containsKey(subtask.getId())) return; + Subtask existingSubtask = subtasks.get(subtask.getId()); + if (existingSubtask.getEpicId() != subtask.getEpicId()) { + throw new IllegalArgumentException("Cannot change epicId of subtask"); + } + if (checkTimeIntersection(subtask)) { throw new IllegalArgumentException("Subtask time overlaps with another task"); } - prioritizedTasks.remove(subtasks.get(subtask.getId())); + + prioritizedTasks.remove(existingSubtask); subtasks.put(subtask.getId(), subtask); prioritizedTasks.add(subtask); updateEpicFields(epics.get(subtask.getEpicId()));