diff --git a/java-kanban.iml b/java-kanban.iml
index 635e7f3..2642f22 100644
--- a/java-kanban.iml
+++ b/java-kanban.iml
@@ -40,5 +40,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Main.java b/src/Main.java
index 428cc9c..0b824b0 100644
--- a/src/Main.java
+++ b/src/Main.java
@@ -5,6 +5,9 @@
import tasks.Subtask;
import tasks.Task;
+import java.time.Duration;
+import java.time.LocalDateTime;
+
public class Main {
public static void main(String[] args) {
@@ -12,8 +15,8 @@ public static void main(String[] args) {
TaskManager taskManager = Managers.getDefault();
// Создаем задачи и добавляем их в managers.TaskManager
- Task task1 = new Task("Закупка продуктов", "Купить все для праздничного ужина.", Status.NEW);
- Task task2 = new Task("Планирование тренировки", "Составить план тренировок на месяц.", Status.NEW);
+ Task task1 = new Task("Закупка продуктов", "Купить все для праздничного ужина.", Status.NEW, Duration.ofMinutes(60), LocalDateTime.now());
+ Task task2 = new Task("Планирование тренировки", "Составить план тренировок на месяц.", Status.NEW, Duration.ofMinutes(60), LocalDateTime.now());
taskManager.addTask(task1);
taskManager.addTask(task2);
diff --git a/src/managers/FileBackedTaskManager.java b/src/managers/FileBackedTaskManager.java
index a4a3b21..b01770e 100644
--- a/src/managers/FileBackedTaskManager.java
+++ b/src/managers/FileBackedTaskManager.java
@@ -10,40 +10,16 @@
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
+import java.time.Duration;
+import java.time.LocalDateTime;
import java.util.List;
+import java.util.stream.Stream;
public class FileBackedTaskManager extends InMemoryTaskManager {
- public static void main(String[] args) {
- File file = new File("tasks.csv");
- InMemoryHistoryManager inMemoryHistoryManager = new InMemoryHistoryManager();
-
- FileBackedTaskManager manager = new FileBackedTaskManager(file, inMemoryHistoryManager);
-
- Task task = new Task("Task1", "Description task", Status.NEW);
- Epic epic = new Epic("Epic1", "Description epic", Status.IN_PROGRESS);
- Subtask subtask = new Subtask("Subtask", "Description subtask", Status.NEW, epic.getId());
-
- manager.addTask(task);
- manager.addEpic(epic);
- manager.addSubtask(subtask);
-
- System.out.println("до сохранения:\n");
- System.out.println(manager.getAllTasks());
- System.out.println(manager.getAllEpic());
- System.out.println(manager.getAllSubtask());
-
- FileBackedTaskManager loaderManager = FileBackedTaskManager.loadFromFile(file, inMemoryHistoryManager);
-
- System.out.println("после загрузки:\n");
- System.out.println(loaderManager.getAllTasks());
- System.out.println(loaderManager.getAllEpic());
- System.out.println(loaderManager.getAllSubtask());
- }
-
private final File file;
- public FileBackedTaskManager(File file, InMemoryHistoryManager inMemoryHistoryManager) {
- super(inMemoryHistoryManager);
+ public FileBackedTaskManager(File file, InMemoryHistoryManager historyManager) {
+ super(historyManager);
this.file = file;
}
@@ -113,81 +89,111 @@ public void addSubtask(Subtask subtask) {
save();
}
- public static FileBackedTaskManager loadFromFile(File file, InMemoryHistoryManager inMemoryHistoryManager) {
- FileBackedTaskManager manager = new FileBackedTaskManager(file, inMemoryHistoryManager);
- try {
- List lines = Files.readAllLines(file.toPath());
-
- if (lines.size() < 2) {
- return manager;
- }
+ @Override
+ public void updateSubtask(Subtask subtask) {
+ super.updateSubtask(subtask);
+ save();
+ }
- for (int i = 1; i < lines.size(); i++) {
- Task task = manager.fromString(lines.get(i));
- switch (task.getType()) {
- case TASK:
- manager.addTask(task);
- break;
- case SUBTASK:
- manager.addSubtask((Subtask) task);
- break;
- case EPIC:
- manager.addEpic((Epic) task);
- break;
- }
+ @Override
+ public List getPrioritizedTasks() {
+ return super.getPrioritizedTasks();
+ }
+
+ /**
+ * Загружает менеджер из CSV. Бросает IOException при проблемах с файлом.
+ */
+ public static FileBackedTaskManager loadFromFile(File file,
+ InMemoryHistoryManager historyManager) throws IOException {
+ FileBackedTaskManager manager = new FileBackedTaskManager(file, historyManager);
+ List lines = Files.readAllLines(file.toPath());
+ if (lines.size() < 2) {
+ return manager;
+ }
+ for (int i = 1; i < lines.size(); i++) {
+ Task task = manager.fromString(lines.get(i));
+ switch (task.getType()) {
+ case TASK:
+ manager.addTask(task);
+ break;
+ case SUBTASK:
+ manager.addSubtask((Subtask) task);
+ break;
+ case EPIC:
+ manager.addEpic((Epic) task);
+ break;
}
- } catch (IOException e) {
- throw new ManagerSaveException("При загрузке файла произошла ошибка: ", e);
}
return manager;
}
-
protected void save() {
- try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file))) {
- bufferedWriter.write("id,type,name,status,description,epic\n");
-
- for (Task task : getAllTasks()) {
- bufferedWriter.write(toString(task) + "\n");
- }
-
- for (Subtask subtask : getAllSubtask()) {
- bufferedWriter.write(toString(subtask) + "\n");
- }
-
- for (Epic epic : getAllEpic()) {
- bufferedWriter.write(toString(epic) + "\n");
- }
+ try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
+ writer.write("id,type,name,status,description,StartTime,duration,epic\n");
+ Stream.concat(
+ Stream.concat(
+ getAllTasks().stream(),
+ getAllSubtask().stream()
+ ),
+ getAllEpic().stream()
+ ).forEach(task -> {
+ try {
+ writer.write(toString(task));
+ writer.newLine();
+ } catch (IOException e) {
+ throw new ManagerSaveException("Ошибка при записи задачи в файл", e);
+ }
+ });
} catch (IOException e) {
- throw new ManagerSaveException("Ошибка в сохранении файла");
+ throw new ManagerSaveException("Ошибка в сохранении файла", e);
}
}
private String toString(Task task) {
- String description = task.getDescription().replace(",", " "); //добавил в случае, если в описании будет запятая
- return String.format("%d,%s,%s,%s,%s,%s",
- task.getId(), task.getType(), task.getName(), task.getStatus(), description,
- (task instanceof Subtask) ? ((Subtask) task).getEpicId() : ""
+ String description = task.getDescription().replace(",", " ");
+ String startTime = task.getStartTime() == null ? "null" : task.getStartTime().toString();
+ String duration = task.getDuration() == null ? "0" : String.valueOf(task.getDuration().toMinutes());
+ String epicId = task instanceof Subtask ? String.valueOf(((Subtask) task).getEpicId()) : "";
+ return String.format("%d,%s,%s,%s,%s,%s,%s,%s",
+ task.getId(), task.getType(), task.getName(), task.getStatus(),
+ description, startTime, duration, epicId
);
}
private Task fromString(String line) {
- String[] parts = line.split(",", 6);
-
+ String[] parts = line.split(",", 8);
+ if (parts.length < 8) {
+ throw new IllegalArgumentException("Недостаточно данных для разбора строки: " + line);
+ }
int id = Integer.parseInt(parts[0]);
TypeOfTask type = TypeOfTask.valueOf(parts[1]);
String name = parts[2];
Status status = Status.valueOf(parts[3]);
String description = parts[4];
+ String startTimeStr = parts[5];
+ long minutes = Long.parseLong(parts[6]);
+ Duration duration = Duration.ofMinutes(minutes);
+ String epicIdStr = parts[7];
+
+ LocalDateTime startTime = startTimeStr.equals("null") ? null : LocalDateTime.parse(startTimeStr);
switch (type) {
case TASK:
- return new Task(name, description, status);
+ Task task = new Task(name, description, status, duration, startTime);
+ task.setId(id);
+ return task;
case SUBTASK:
- int epicId = Integer.parseInt(parts[5]);
- return new Subtask(name, description, status, epicId);
+ if (epicIdStr.isEmpty()) {
+ throw new IllegalArgumentException("ИД Эпика не может быть пустым");
+ }
+ int epicId = Integer.parseInt(epicIdStr);
+ Subtask subtask = new Subtask(name, description, status, epicId, duration, startTime);
+ subtask.setId(id);
+ return subtask;
case EPIC:
- return new Epic(name, description, status);
+ Epic epic = new Epic(name, description, status);
+ epic.setId(id);
+ return epic;
default:
throw new IllegalArgumentException("Задача неизвестного типа: " + type);
}
diff --git a/src/managers/InMemoryHistoryManager.java b/src/managers/InMemoryHistoryManager.java
index 88e5c64..0e3ac8d 100644
--- a/src/managers/InMemoryHistoryManager.java
+++ b/src/managers/InMemoryHistoryManager.java
@@ -28,6 +28,10 @@ private void addLast(Task task) {
@Override
public void add(Task task) {
+ if (task == null) {
+ return;
+ }
+
if (historyMap.containsKey(task.getId())) {
remove(task.getId());
}
diff --git a/src/managers/InMemoryTaskManager.java b/src/managers/InMemoryTaskManager.java
index f804bb8..85680a2 100644
--- a/src/managers/InMemoryTaskManager.java
+++ b/src/managers/InMemoryTaskManager.java
@@ -5,17 +5,20 @@
import tasks.Subtask;
import tasks.Task;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
+import java.util.*;
+import java.util.stream.Collectors;
public class InMemoryTaskManager implements TaskManager {
private int idCounter = 0;
- private final HashMap tasks = new HashMap<>();
- private final HashMap epics = new HashMap<>();
- private final HashMap subtasks = new HashMap<>();
+ private final Map tasks = new HashMap<>();
+ private final Map epics = new HashMap<>();
+ private final Map subtasks = new HashMap<>();
private final HistoryManager historyManager;
+ private final TreeSet prioritizedTasks = new TreeSet<>(
+ Comparator.comparing(Task::getStartTime, Comparator.nullsLast(Comparator.naturalOrder()))
+ );
+
public InMemoryTaskManager(HistoryManager historyManager) {
this.historyManager = historyManager;
}
@@ -25,25 +28,40 @@ public int createId() {
return idCounter++;
}
+ private boolean isOverlappingInternal(Task newTask) {
+ if (newTask.getStartTime() == null || newTask.getDuration() == null) {
+ return false;
+ }
+ return prioritizedTasks.stream()
+ .filter(t -> t.getStartTime() != null && t.getDuration() != null)
+ .anyMatch(existing -> existing.overlapsWith(newTask));
+ }
+
@Override
public void addTask(Task task) {
+ if (isOverlappingInternal(task)) {
+ throw new IllegalArgumentException("Задача пересекается по времени");
+ }
task.setId(createId());
tasks.put(task.getId(), task);
+ prioritizedTasks.add(task);
}
@Override
public void updateTask(Task task) {
- if (tasks.containsKey(task.getId())) {
- tasks.put(task.getId(), task);
- } else {
- System.out.println("Error");
+ if (isOverlappingInternal(task)) {
+ throw new IllegalArgumentException("Обновлённая задача пересекается по времени");
}
+ tasks.put(task.getId(), task);
+ prioritizedTasks.removeIf(t -> t.getId() == task.getId());
+ prioritizedTasks.add(task);
}
@Override
public Task getTask(int id) {
- historyManager.add(tasks.get(id));
- return tasks.get(id);
+ Task t = tasks.get(id);
+ historyManager.add(t);
+ return t;
}
@Override
@@ -53,24 +71,35 @@ public List getAllTasks() {
@Override
public void removeAllTasks() {
+ tasks.values().forEach(prioritizedTasks::remove);
tasks.clear();
}
@Override
public void removeAllSubtasks() {
+ subtasks.values().forEach(prioritizedTasks::remove);
subtasks.clear();
+ epics.values().forEach(epic -> {
+ epic.getSubtasks().clear();
+ updateStatusForEpic(epic);
+ epic.calculateTime(Collections.emptyList());
+ });
}
@Override
public void removeAllEpics() {
+ epics.values().forEach(epic -> {
+ epic.getSubtasks().forEach(id -> prioritizedTasks.remove(subtasks.get(id)));
+ subtasks.keySet().removeAll(epic.getSubtasks());
+ });
epics.clear();
- subtasks.clear();
}
@Override
public void removeTaskById(int id) {
- historyManager.add(tasks.get(id));
- tasks.remove(id);
+ Task t = tasks.remove(id);
+ historyManager.add(t);
+ prioritizedTasks.remove(t);
}
@Override
@@ -82,90 +111,68 @@ public void addEpic(Epic epic) {
@Override
public void removeEpicById(int id) {
- Epic epic = epics.get(id);
-
+ Epic epic = epics.remove(id);
if (epic != null) {
- for (int subtaskId : epic.getSubtasks()) {
- subtasks.remove(subtaskId);
- }
-
- epics.remove(id);
- } else {
- System.out.println("Error");
+ epic.getSubtasks().forEach(subId -> {
+ Subtask st = subtasks.remove(subId);
+ prioritizedTasks.remove(st);
+ });
}
}
@Override
public void removeSubtaskId(int id) {
- Subtask subtask = subtasks.get(id);
-
- if (subtask != null) {
-
- Epic epic = epics.get(subtask.getEpicId());
-
+ Subtask sub = subtasks.remove(id);
+ if (sub != null) {
+ historyManager.add(sub);
+ prioritizedTasks.remove(sub);
+ Epic epic = epics.get(sub.getEpicId());
if (epic != null) {
epic.getSubtasks().remove(Integer.valueOf(id));
updateStatusForEpic(epic);
+ epic.calculateTime(getEpicSubtasks(epic.getId()));
}
-
- historyManager.add(subtask);
- } else {
- System.out.println("Error");
}
}
-
@Override
public void updateStatusForEpic(Epic epic) {
- if (epic.getSubtasks().isEmpty()) {
+ List statuses = epic.getSubtasks().stream()
+ .map(subtasks::get)
+ .filter(Objects::nonNull)
+ .map(Subtask::getStatus)
+ .collect(Collectors.toList());
+ if (statuses.isEmpty()) {
epic.setStatus(Status.NEW);
- return;
- }
-
- boolean isAllNew = true;
- boolean isAllDone = true;
-
- for (int id : epic.getSubtasks()) {
- Subtask subtask = subtasks.get(id);
-
- if (subtask != null) {
- if (subtask.getStatus() != Status.NEW) {
- isAllNew = false;
- }
- if (subtask.getStatus() != Status.DONE) {
- isAllDone = false;
- }
- }
- }
-
- if (isAllNew) {
+ } else if (statuses.stream().allMatch(s -> s == Status.NEW)) {
epic.setStatus(Status.NEW);
- } else if (isAllDone) {
+ } else if (statuses.stream().allMatch(s -> s == Status.DONE)) {
epic.setStatus(Status.DONE);
} else {
epic.setStatus(Status.IN_PROGRESS);
}
-
}
@Override
public void addSubtask(Subtask subtask) {
+ if (!epics.containsKey(subtask.getEpicId())) {
+ throw new IllegalArgumentException("Добавление подзадачи с несуществующим ID эпика");
+ }
+
+ if (isOverlappingInternal(subtask)) {
+ throw new IllegalArgumentException("Подзадача пересекается по времени");
+ }
subtask.setId(createId());
subtasks.put(subtask.getId(), subtask);
-
-
+ prioritizedTasks.add(subtask);
Epic epic = epics.get(subtask.getEpicId());
if (epic != null) {
epic.getSubtasks().add(subtask.getId());
updateStatusForEpic(epic);
- } else {
- System.out.println("Ошибка: эпик не найден!");
+ epic.calculateTime(getEpicSubtasks(epic.getId()));
}
-
- historyManager.add(subtask);
}
-
@Override
public List getAllSubtask() {
return new ArrayList<>(subtasks.values());
@@ -173,22 +180,23 @@ public List getAllSubtask() {
@Override
public Subtask getSubtaskById(int id) {
- historyManager.add(subtasks.get(id));
- return subtasks.get(id);
+ Subtask s = subtasks.get(id);
+ historyManager.add(s);
+ return s;
}
@Override
public void updateSubtask(Subtask subtask) {
- if (subtasks.containsKey(subtask.getId())) {
- subtasks.put(subtask.getId(), subtask);
-
- Epic epic = epics.get(subtask.getEpicId());
-
- if (epic != null) {
- updateStatusForEpic(epic);
- }
- } else {
- System.out.println("Error");
+ if (isOverlappingInternal(subtask)) {
+ throw new IllegalArgumentException("Обновлённая подзадача пересекается по времени");
+ }
+ subtasks.put(subtask.getId(), subtask);
+ prioritizedTasks.removeIf(t -> t.getId() == subtask.getId());
+ prioritizedTasks.add(subtask);
+ Epic epic = epics.get(subtask.getEpicId());
+ if (epic != null) {
+ updateStatusForEpic(epic);
+ epic.calculateTime(getEpicSubtasks(epic.getId()));
}
}
@@ -196,30 +204,22 @@ public void updateSubtask(Subtask subtask) {
public void updateEpic(Epic epic) {
if (epics.containsKey(epic.getId())) {
epics.put(epic.getId(), epic);
- } else {
- System.out.println("Error");
}
}
-
@Override
public List getEpicSubtasks(int epicId) {
Epic epic = epics.get(epicId);
- List epicSubtasks = new ArrayList<>();
- if (epic != null) {
- for (int subtaskId : epic.getSubtasks()) {
- Subtask subtask = subtasks.get(subtaskId);
- if (subtask != null) {
- epicSubtasks.add(subtask);
- }
- }
+ if (epic == null) {
+ return Collections.emptyList();
}
historyManager.add(epic);
-
- return epicSubtasks;
+ return epic.getSubtasks().stream()
+ .map(subtasks::get)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
}
-
@Override
public List getAllEpic() {
return new ArrayList<>(epics.values());
@@ -229,4 +229,8 @@ public List getAllEpic() {
public List getHistory() {
return historyManager.getHistory();
}
+
+ public List getPrioritizedTasks() {
+ return new ArrayList<>(prioritizedTasks);
+ }
}
diff --git a/src/tasks/Epic.java b/src/tasks/Epic.java
index f66c8e8..abee1a0 100644
--- a/src/tasks/Epic.java
+++ b/src/tasks/Epic.java
@@ -2,16 +2,24 @@
import managers.TypeOfTask;
+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 subtasks;
+ private Duration duration;
+ private LocalDateTime startTime;
+ private LocalDateTime endTime;
public Epic(String name, String description, Status status) {
- super(name, description, status);
+ super(name, description, status, Duration.ZERO, null);
this.subtasks = new ArrayList<>();
this.type = TypeOfTask.EPIC;
+ this.startTime = null;
+ this.endTime = null;
}
public List getSubtasks() {
@@ -19,10 +27,69 @@ public List getSubtasks() {
}
public void addSubtaskId(int id) {
+ System.out.println("Adding subtask ID: " + id + ", Epic ID: " + getId());
+ if (id == getId()) {
+ throw new IllegalArgumentException("Эпик не может содержать себя в качестве подзадачи.");
+ }
subtasks.add(id);
}
+ public void calculateTime(List subtasks) {
+ if (subtasks == null || subtasks.isEmpty()) {
+ this.duration = Duration.ZERO;
+ this.startTime = null;
+ this.endTime = null;
+ return;
+ }
+ Duration totalSubtaskDuration = subtasks.stream()
+ .map(Subtask::getDuration)
+ .filter(Objects::nonNull)
+ .reduce(Duration.ZERO, Duration::plus);
+
+ LocalDateTime minSubtaskStartTime = subtasks.stream()
+ .map(Subtask::getStartTime)
+ .filter(Objects::nonNull)
+ .min(LocalDateTime::compareTo)
+ .orElse(null);
+
+ LocalDateTime maxSubtaskEndTime = subtasks.stream()
+ .filter(sub -> sub.getStartTime() != null && sub.getDuration() != null)
+ .map(sub -> sub.getStartTime().plus(sub.getDuration()))
+ .max(LocalDateTime::compareTo)
+ .orElse(null);
+
+ setDuration(totalSubtaskDuration);
+ setStartTime(minSubtaskStartTime);
+ setEndTime(maxSubtaskEndTime);
+ }
+
+ public void updateStatus(List subtasks) {
+ if (subtasks == null || subtasks.isEmpty()) {
+ setStatus(Status.NEW);
+ return;
+ }
+
+ boolean allNew = subtasks.stream().allMatch(sub -> sub.getStatus() == Status.NEW);
+ boolean allDone = subtasks.stream().allMatch(sub -> sub.getStatus() == Status.DONE);
+
+ if (allNew) {
+ setStatus(Status.NEW);
+ } else if (allDone) {
+ setStatus(Status.DONE);
+ } else {
+ setStatus(Status.IN_PROGRESS);
+ }
+ }
+
+ @Override
+ public LocalDateTime getEndTime() {
+ return endTime;
+ }
+
+ public void setEndTime(LocalDateTime endTime) {
+ this.endTime = endTime;
+ }
@Override
public String toString() {
@@ -32,6 +99,9 @@ public String toString() {
", subTasks=" + subtasks +
", status=" + getStatus() +
", id=" + getId() +
+ ", duration=" + getDuration() +
+ ", startTime=" + getStartTime() +
+ ", endTime=" + getEndTime() +
'}';
}
-}
+}
\ No newline at end of file
diff --git a/src/tasks/Subtask.java b/src/tasks/Subtask.java
index b3f190e..c9b98e1 100644
--- a/src/tasks/Subtask.java
+++ b/src/tasks/Subtask.java
@@ -2,27 +2,49 @@
import managers.TypeOfTask;
+import java.time.Duration;
+import java.time.LocalDateTime;
+
public class Subtask extends Task {
- private int epicId;
+ private final int epicId;
public Subtask(String name, String description, Status status, int epicId) {
- super(name, description, status);
+ super(name, description, status, Duration.ZERO, null);
+ this.epicId = epicId;
+ this.type = TypeOfTask.SUBTASK;
+ }
+
+ public Subtask(String name, String description, Status status, int epicId,
+ Duration duration, LocalDateTime startTime) {
+ super(name, description, status, duration, startTime);
this.epicId = epicId;
this.type = TypeOfTask.SUBTASK;
}
+ @Override
+ public void setId(int newId) {
+ // Не позволяем устанавливать ID подзадачи равным её epicId
+ if (newId == this.epicId) {
+ return;
+ }
+ super.setId(newId);
+ }
+
public int getEpicId() {
return epicId;
}
@Override
public String toString() {
- return "tasks.Subtask{" +
+ return "Subtask{" +
"name='" + getName() + '\'' +
", description='" + getDescription() + '\'' +
", status=" + getStatus() +
", id=" + getId() +
+ ", epicId=" + epicId +
+ ", startTime=" + getStartTime() +
+ ", duration=" + getDuration() +
'}';
}
-}
+}
\ No newline at end of file
diff --git a/src/tasks/Task.java b/src/tasks/Task.java
index 2b3ce13..c0da58a 100644
--- a/src/tasks/Task.java
+++ b/src/tasks/Task.java
@@ -2,6 +2,8 @@
import managers.TypeOfTask;
+import java.time.Duration;
+import java.time.LocalDateTime;
import java.util.Objects;
public class Task {
@@ -10,12 +12,20 @@ public class Task {
private Status status;
private int id;
protected TypeOfTask type;
+ private Duration duration;
+ private LocalDateTime startTime;
- public Task(String name, String description, Status status) {
+ public Task(String name, String description, Status status, Duration duration, LocalDateTime startTime) {
this.name = name;
this.description = description;
this.status = status;
this.type = TypeOfTask.TASK;
+ this.duration = duration;
+ this.startTime = startTime;
+ }
+
+ public Task(String name, String description, Status status) {
+ this(name, description, status, null, null);
}
public String getName() {
@@ -47,13 +57,46 @@ public int getId() {
}
public void setId(int newId) {
- id = newId;
+ this.id = newId;
}
public TypeOfTask getType() {
return type;
}
+ 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 null;
+ }
+ return startTime.plus(duration);
+ }
+
+ public boolean overlapsWith(Task otherTask) {
+ if (this.getStartTime() == null || otherTask.getStartTime() == null
+ || this.getDuration() == null || otherTask.getDuration() == null) {
+ return false;
+ }
+ LocalDateTime thisEnd = this.getEndTime();
+ LocalDateTime otherEnd = otherTask.getEndTime();
+ return this.getStartTime().isBefore(otherEnd) && thisEnd.isAfter(otherTask.getStartTime());
+ }
+
@Override
public String toString() {
return "tasks.Task{" +
@@ -61,6 +104,9 @@ public String toString() {
", description='" + description + '\'' +
", status=" + status +
", id=" + id +
+ ", duration=" + duration +
+ ", startTime=" + startTime +
+ ", endTime=" + getEndTime() +
'}';
}
@@ -69,14 +115,16 @@ public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Task task = (Task) obj;
- return Objects.equals(name, task.name) &&
+ return id == task.id &&
+ Objects.equals(name, task.name) &&
Objects.equals(description, task.description) &&
- Objects.equals(status, task.status);
-
+ status == task.status &&
+ Objects.equals(duration, task.duration) &&
+ Objects.equals(startTime, task.startTime);
}
@Override
public int hashCode() {
- return Objects.hash(name, description, status, id);
+ return Objects.hash(name, description, status, id, duration, startTime);
}
}
diff --git a/test/EpicTest.java b/test/EpicTest.java
index 0fdb53f..6d7927e 100644
--- a/test/EpicTest.java
+++ b/test/EpicTest.java
@@ -1,17 +1,128 @@
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import tasks.Epic;
import tasks.Status;
+import tasks.Subtask;
+
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
class EpicTest {
- @Test
- void epicCannotContainItselfAsSubtask() {
- Epic epic = new Epic("Эпик", "Описание", Status.NEW);
+ private Epic epic;
+ private LocalDateTime base;
+
+ @BeforeEach
+ void setUp() {
+ epic = new Epic("Эпик", "Описание", Status.NEW);
epic.setId(1);
+ base = LocalDateTime.of(2025,4,1,10,0);
+ }
+
+ @Test
+ void epicCannotContainItself() {
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () ->
+ epic.addSubtaskId(epic.getId())
+ );
+ assertEquals("Эпик не может содержать себя в качестве подзадачи.", ex.getMessage());
+ }
+
+ @Test
+ void statusNewWhenNoSubtasks() {
+ epic.updateStatus(new ArrayList<>());
+ assertEquals(Status.NEW, epic.getStatus());
+ }
+
+ @Test
+ void statusNewWhenAllNew() {
+ List subs = List.of(
+ new Subtask("Сабтаска1","", Status.NEW, 1, Duration.ofMinutes(30), base),
+ new Subtask("Сабтаска2","", Status.NEW, 1, Duration.ofMinutes(45), base.plusHours(1))
+ );
+ epic.updateStatus(subs);
+ assertEquals(Status.NEW, epic.getStatus());
+ }
+
+ @Test
+ void statusDoneWhenAllDone() {
+ List subs = List.of(
+ new Subtask("Сабтаска1","", Status.DONE, 1, Duration.ofMinutes(30), base),
+ new Subtask("Сабтаска2","", Status.DONE, 1, Duration.ofMinutes(45), base.plusHours(1))
+ );
+ epic.updateStatus(subs);
+ assertEquals(Status.DONE, epic.getStatus());
+ }
+
+ @Test
+ void statusInProgressWhenMixed() {
+ List subs = List.of(
+ new Subtask("Сабтаска1","", Status.NEW, 1, Duration.ofMinutes(30), base),
+ new Subtask("Сабтаска2","", Status.DONE, 1, Duration.ofMinutes(45), base.plusHours(1))
+ );
+ epic.updateStatus(subs);
+ assertEquals(Status.IN_PROGRESS, epic.getStatus());
+ }
- // Проверка через обычное условие
- boolean isAdded = epic.getSubtasks().contains(epic.getId());
- assertFalse(isAdded, "Ошибка эпика.");
+ @Test
+ void statusInProgressWhenAnyInProgress() {
+ List subs = List.of(
+ new Subtask("Сабтаска1","", Status.IN_PROGRESS, 1, Duration.ofMinutes(30), base),
+ new Subtask("Сабтаска2","", Status.NEW, 1, Duration.ofMinutes(45), base.plusHours(1))
+ );
+ epic.updateStatus(subs);
+ assertEquals(Status.IN_PROGRESS, epic.getStatus());
+ }
+
+ @Test
+ void timeCalculationCorrect() {
+ Subtask a = new Subtask("Сабтаска1","", Status.NEW, 1, Duration.ofMinutes(30), base);
+ Subtask b = new Subtask("Сабтаска2","", Status.DONE, 1, Duration.ofMinutes(45), base.plusHours(1));
+ epic.calculateTime(List.of(a,b));
+
+ assertEquals(Duration.ofMinutes(75), epic.getDuration());
+ assertEquals(base, epic.getStartTime());
+ assertEquals(base.plusHours(1).plusMinutes(45), epic.getEndTime());
+ }
+
+ @Test
+ void timeEmptyWhenNoSubtasks() {
+ epic.calculateTime(new ArrayList<>());
+ assertNull(epic.getStartTime());
+ assertNull(epic.getEndTime());
+ assertEquals(Duration.ZERO, epic.getDuration());
+ }
+
+ @Test
+ void timeIgnoresNulls() {
+ Subtask a = new Subtask("Сабтаска1","", Status.NEW, 1);
+ Subtask b = new Subtask("Сабтаска2","", Status.DONE, 1, Duration.ofMinutes(45), base);
+ epic.calculateTime(List.of(a,b));
+
+ assertEquals(Duration.ofMinutes(45), epic.getDuration());
+ assertEquals(base, epic.getStartTime());
+ assertEquals(base.plusMinutes(45), epic.getEndTime());
+ }
+
+ @Test
+ void addSubtaskIdUpdatesList() {
+ epic.addSubtaskId(5);
+ epic.addSubtaskId(7);
+ assertTrue(epic.getSubtasks().containsAll(List.of(5,7)));
+ }
+
+ @Test
+ void toStringContainsAllFields() {
+ List subs = List.of(
+ new Subtask("Сабтаска1","", Status.NEW, 1, Duration.ofMinutes(30), base)
+ );
+ epic.calculateTime(subs);
+ epic.updateStatus(subs);
+ String s = epic.toString();
+ assertTrue(s.contains("E"));
+ assertTrue(s.contains("PT30M"));
+ assertTrue(s.contains(base.toString()));
}
}
diff --git a/test/InMemoryTaskManagerTest.java b/test/InMemoryTaskManagerTest.java
index 5816746..309aecc 100644
--- a/test/InMemoryTaskManagerTest.java
+++ b/test/InMemoryTaskManagerTest.java
@@ -1,44 +1,14 @@
import managers.InMemoryHistoryManager;
import managers.InMemoryTaskManager;
-import managers.TaskManager;
-import org.junit.jupiter.api.Test;
-import tasks.Status;
-import tasks.Task;
+import managers.TaskManagerTest;
+import org.junit.jupiter.api.BeforeEach;
-import static org.junit.jupiter.api.Assertions.*;
+public class InMemoryTaskManagerTest extends TaskManagerTest {
-class InMemoryTaskManagerTest {
- @Test
- void addAndGetTaskById() {
- TaskManager taskManager = new InMemoryTaskManager(new InMemoryHistoryManager());
- Task task = new Task("Задача", "Описание", Status.NEW);
- taskManager.addTask(task);
- Task retrievedTask = taskManager.getTask(task.getId());
- assertEquals(task, retrievedTask, "Задача должна корректно находиться по ID.");
+ @BeforeEach
+ @Override
+ public void setUp() {
+ // История нужна только для TaskManager; она не влияет на логику add/update/remove/...
+ taskManager = new InMemoryTaskManager(new InMemoryHistoryManager());
}
-
- @Test
- void tasksWithGeneratedAndSpecifiedIdsDoNotConflict() {
- TaskManager taskManager = new InMemoryTaskManager(new InMemoryHistoryManager());
- Task task1 = new Task("Задача 1", "Описание 1", Status.NEW);
- task1.setId(1);
- taskManager.addTask(task1);
-
- Task task2 = new Task("Задача 2", "Описание 2", Status.NEW);
- taskManager.addTask(task2);
-
- assertNotEquals(task1.getId(), task2.getId(), "ID не должны конфликтовать.");
- }
-
- @Test
- void taskFieldsRemainUnchangedAfterAddition() {
- TaskManager taskManager = new InMemoryTaskManager(new InMemoryHistoryManager());
- Task task = new Task("Задача", "Описание", Status.NEW);
- taskManager.addTask(task);
- Task retrievedTask = taskManager.getTask(task.getId());
-
- assertEquals("Задача", retrievedTask.getName(), "Имя задачи должно оставаться неизменным.");
- assertEquals("Описание", retrievedTask.getDescription(), "Описание задачи должно оставаться неизменным.");
- assertEquals(Status.NEW, retrievedTask.getStatus(), "Статус задачи должен оставаться неизменным.");
- }
-}
+}
\ No newline at end of file
diff --git a/test/SubtaskTest.java b/test/SubtaskTest.java
index 0002159..52107b6 100644
--- a/test/SubtaskTest.java
+++ b/test/SubtaskTest.java
@@ -1,17 +1,91 @@
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import tasks.Status;
import tasks.Subtask;
+import java.time.Duration;
+import java.time.LocalDateTime;
+
import static org.junit.jupiter.api.Assertions.*;
class SubtaskTest {
+ private LocalDateTime base;
+ private int epicId = 1;
+
+ @BeforeEach
+ void setUp() {
+ base = LocalDateTime.of(2023,1,1,10,0);
+ }
+
+ @Test
+ void cannotHaveItselfAsEpic() {
+ Subtask s = new Subtask("Сабтаска","", Status.NEW, epicId);
+ s.setId(epicId);
+ assertFalse(s.getEpicId() == s.getId(),
+ "Подзадача не может быть своим же эпиком.");
+ }
+
+ @Test
+ void partialOverlap() {
+ Subtask a = new Subtask("Сабтаска1","", Status.NEW, 1,
+ Duration.ofMinutes(60), base);
+ Subtask b = new Subtask("Сабтаска2","", Status.NEW, 1,
+ Duration.ofMinutes(60), base.plusMinutes(30));
+ assertTrue(a.overlapsWith(b));
+ assertTrue(b.overlapsWith(a));
+ }
+
+ @Test
+ void fullOverlap() {
+ Subtask a = new Subtask("Сабтаска1","", Status.NEW, 1,
+ Duration.ofMinutes(60), base);
+ Subtask b = new Subtask("Сабтаска2","", Status.NEW, 1,
+ Duration.ofMinutes(60), base);
+ assertTrue(a.overlapsWith(b));
+ }
+
+ @Test
+ void containedOverlap() {
+ Subtask a = new Subtask("Сабтаска1","", Status.NEW, 1,
+ Duration.ofMinutes(120), base);
+ Subtask b = new Subtask("Сабтаска2","", Status.NEW, 1,
+ Duration.ofMinutes(30), base.plusMinutes(30));
+ assertTrue(a.overlapsWith(b));
+ }
+
+ @Test
+ void noOverlap() {
+ Subtask a = new Subtask("Сабтаска1","", Status.NEW, 1,
+ Duration.ofMinutes(60), base);
+ Subtask b = new Subtask("Сабтаска2","", Status.NEW, 1,
+ Duration.ofMinutes(60), base.plusHours(2));
+ assertFalse(a.overlapsWith(b));
+ }
+
+ @Test
+ void touchingNoOverlap() {
+ Subtask a = new Subtask("Сабтаска1","", Status.NEW, 1,
+ Duration.ofMinutes(60), base);
+ Subtask b = new Subtask("Сабтаска2","", Status.NEW, 1,
+ Duration.ofMinutes(60), base.plusMinutes(60));
+ assertFalse(a.overlapsWith(b));
+ }
+
@Test
- void subtaskCannotHaveItselfAsEpic() {
- Subtask subtask = new Subtask("Подзадача", "Описание", Status.NEW, 1);
- subtask.setId(2);
+ void nullStartOrNullDurationNoOverlap() {
+ Subtask a = new Subtask("Сабтаска1","", Status.NEW, 1, null, base);
+ Subtask b = new Subtask("Сабтаска2","", Status.NEW, 1,
+ Duration.ofMinutes(60), null);
+ assertFalse(a.overlapsWith(b));
+ assertFalse(b.overlapsWith(a));
+ }
- // Проверка на то, что эпик не равен id подзадачи
- boolean isInvalidEpic = subtask.getEpicId() == subtask.getId();
- assertFalse(isInvalidEpic, "Подзадача не может быть своим же эпиком.");
+ @Test
+ void zeroDurationNoOverlap() {
+ Subtask a = new Subtask("Сабтаска1","", Status.NEW, 1,
+ Duration.ZERO, base);
+ Subtask b = new Subtask("Сабтаска2","", Status.NEW, 1,
+ Duration.ofMinutes(60), base);
+ assertFalse(a.overlapsWith(b));
}
}
diff --git a/test/TaskTest.java b/test/TaskTest.java
index 4870aec..df587bb 100644
--- a/test/TaskTest.java
+++ b/test/TaskTest.java
@@ -1,26 +1,89 @@
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import tasks.Status;
-import tasks.Subtask;
import tasks.Task;
+import java.time.Duration;
+import java.time.LocalDateTime;
+
import static org.junit.jupiter.api.Assertions.*;
class TaskTest {
+ private LocalDateTime base;
+
+ @BeforeEach
+ void setUp() {
+ base = LocalDateTime.of(2025,4,1,10,0);
+ }
+
+ @Test
+ void equalById() {
+ Task a = new Task("Таск","", Status.NEW);
+ Task b = new Task("Таск","", Status.NEW);
+ a.setId(5);
+ b.setId(5);
+ assertEquals(a, b);
+ }
+
+ @Test
+ void partialOverlap() {
+ Task a = new Task("Таск1","", Status.NEW,
+ Duration.ofMinutes(60), base);
+ Task b = new Task("Таск2","", Status.NEW,
+ Duration.ofMinutes(60), base.plusMinutes(30));
+ assertTrue(a.overlapsWith(b));
+ }
+
+ @Test
+ void fullOverlap() {
+ Task a = new Task("Таск1","", Status.NEW,
+ Duration.ofMinutes(60), base);
+ Task b = new Task("Таск2","", Status.NEW,
+ Duration.ofMinutes(60), base);
+ assertTrue(a.overlapsWith(b));
+ }
+
+ @Test
+ void containedOverlap() {
+ Task a = new Task("Таск1","", Status.NEW,
+ Duration.ofMinutes(120), base);
+ Task b = new Task("Таск2","", Status.NEW,
+ Duration.ofMinutes(30), base.plusMinutes(30));
+ assertTrue(a.overlapsWith(b));
+ }
+
+ @Test
+ void noOverlap() {
+ Task a = new Task("Таск1","", Status.NEW,
+ Duration.ofMinutes(60), base);
+ Task b = new Task("Таск2","", Status.NEW,
+ Duration.ofMinutes(60), base.plusHours(2));
+ assertFalse(a.overlapsWith(b));
+ }
+
+ @Test
+ void touchingNoOverlap() {
+ Task a = new Task("Таск1","", Status.NEW,
+ Duration.ofMinutes(60), base);
+ Task b = new Task("Таск2","", Status.NEW,
+ Duration.ofMinutes(60), base.plusMinutes(60));
+ assertFalse(a.overlapsWith(b));
+ }
+
@Test
- void tasksAreEqualIfIdsAreEqual() {
- Task task1 = new Task("tasks.Task 1", "", Status.NEW);
- Task task2 = new Task("tasks.Task 1", "", Status.NEW);
- task1.setId(1);
- task2.setId(1);
- assertEquals(task1, task2, "Tаски с одинаковым ID должны быть равны");
+ void nullStartOrNullDurationNoOverlap() {
+ Task a = new Task("Таск1","", Status.NEW, null, base);
+ Task b = new Task("Таск2","", Status.NEW,
+ Duration.ofMinutes(60), null);
+ assertFalse(a.overlapsWith(b));
}
@Test
- void subtasksAreEqualIfIdsAreEqual() {
- Subtask subtask1 = new Subtask("tasks.Subtask 1", "", Status.NEW, 0);
- Subtask subtask2 = new Subtask("tasks.Subtask 1", "", Status.NEW, 0);
- subtask1.setId(1);
- subtask2.setId(1);
- assertEquals(subtask1, subtask2, "Субтаски с одинаковым ID должны быть равны");
+ void zeroDurationNoOverlap() {
+ Task a = new Task("Таск1","", Status.NEW,
+ Duration.ZERO, base);
+ Task b = new Task("Таск2","", Status.NEW,
+ Duration.ofMinutes(60), base);
+ assertFalse(a.overlapsWith(b));
}
}
diff --git a/test/managers/FileBackedTaskManagerTest.java b/test/managers/FileBackedTaskManagerTest.java
index 6872a37..a83c61e 100644
--- a/test/managers/FileBackedTaskManagerTest.java
+++ b/test/managers/FileBackedTaskManagerTest.java
@@ -1,71 +1,23 @@
package managers;
-import org.junit.jupiter.api.Test;
-import tasks.Status;
-import tasks.Task;
-
+import org.junit.jupiter.api.BeforeEach;
import java.io.File;
import java.io.IOException;
-import java.nio.file.Files;
-import java.util.List;
-
-import static org.junit.jupiter.api.Assertions.*;
-
-class FileBackedTaskManagerTest {
- @Test
- public void shouldSaveAndLoadEmptyFile() throws IOException {
- File file = File.createTempFile("tempFile", ".csv");
- file.deleteOnExit();
-
- FileBackedTaskManager manager = new FileBackedTaskManager(file, new InMemoryHistoryManager());
- manager.save();
-
- FileBackedTaskManager loaderManager = FileBackedTaskManager.loadFromFile(file, new InMemoryHistoryManager());
-
- assertTrue(loaderManager.getAllTasks().isEmpty());
- assertTrue(loaderManager.getAllSubtask().isEmpty());
- assertTrue(loaderManager.getAllEpic().isEmpty());
- }
-
- @Test
- public void saveAndLoadMultipleTasks() throws IOException {
- File file = File.createTempFile("tempFile", ".csv");
- file.deleteOnExit();
-
- FileBackedTaskManager manager = new FileBackedTaskManager(file, new InMemoryHistoryManager());
-
- Task task1 = new Task("Task1", " ", Status.NEW);
- Task task2 = new Task("Task2", " ", Status.NEW);
- manager.addTask(task1);
- manager.addTask(task2);
-
- List lines = Files.readAllLines(file.toPath());
-
- assertEquals(3, lines.size());
- assertTrue(lines.get(1).contains("Task1"));
- assertTrue(lines.get(2).contains("Task2"));
- }
-
- @Test
- public void loadTasksSuccessfullyFromFile() throws IOException {
- File file = File.createTempFile("tempFile", ".csv");
- file.deleteOnExit();
-
- FileBackedTaskManager manager = new FileBackedTaskManager(file, new InMemoryHistoryManager());
-
- Task task1 = new Task("Task1", " ", Status.NEW);
- Task task2 = new Task("Task2", " ", Status.NEW);
-
- manager.addTask(task1);
- manager.addTask(task2);
- manager.save();
-
- FileBackedTaskManager loaderManager = FileBackedTaskManager.loadFromFile(file, new InMemoryHistoryManager());
-
- assertEquals(2, loaderManager.getAllTasks().size());
- assertEquals("Task1", loaderManager.getAllTasks().get(0).getName());
- assertEquals("Task2", loaderManager.getAllTasks().get(1).getName());
+public class FileBackedTaskManagerTest
+ extends TaskManagerTest {
+
+ private File file;
+
+ @BeforeEach
+ @Override
+ public void setUp() {
+ try {
+ file = File.createTempFile("tempFile", ".csv");
+ file.deleteOnExit();
+ taskManager = new FileBackedTaskManager(file, new InMemoryHistoryManager());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
-
-}
\ No newline at end of file
+}
diff --git a/test/managers/TaskManagerTest.java b/test/managers/TaskManagerTest.java
new file mode 100644
index 0000000..94bd2af
--- /dev/null
+++ b/test/managers/TaskManagerTest.java
@@ -0,0 +1,123 @@
+package managers;
+
+import tasks.Task;
+import tasks.Epic;
+import tasks.Subtask;
+import tasks.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.*;
+
+public abstract class TaskManagerTest {
+ protected T taskManager;
+ protected LocalDateTime baseTime;
+
+ @BeforeEach
+ public abstract void setUp();
+
+ @Test
+ public void testAddAndGetTask() {
+ Task task = new Task("Таск", "Описание", Status.NEW);
+ taskManager.addTask(task);
+ Task retrieved = taskManager.getTask(task.getId());
+ assertEquals(task, retrieved, "Задача должна быть доступна по ID");
+ }
+
+ @Test
+ public void testUpdateTask() {
+ Task task = new Task("Таск", "Описание", Status.NEW);
+ taskManager.addTask(task);
+ task.setName("Обновленное название");
+ taskManager.updateTask(task);
+ Task retrieved = taskManager.getTask(task.getId());
+ assertEquals("Обновленное название", retrieved.getName(), "Имя задачи должно быть обновлено");
+ }
+
+ @Test
+ public void testDeleteTask() {
+ Task task = new Task("Таск", "Описание", Status.NEW);
+ taskManager.addTask(task);
+ taskManager.removeTaskById(task.getId());
+ assertNull(taskManager.getTask(task.getId()), "Задача должна быть удалена");
+ }
+
+ @Test
+ public void testAddAndGetEpic() {
+ Epic epic = new Epic("Эпик", "Описание", Status.NEW);
+ taskManager.addEpic(epic);
+ Epic retrieved = getEpicById(epic.getId());
+ assertEquals(epic, retrieved, "Эпик должен быть доступен по ID");
+ }
+
+ @Test
+ public void testAddSubtaskToEpic() {
+ Epic epic = new Epic("Эпик", "Описание", Status.NEW);
+ taskManager.addEpic(epic);
+ Subtask subtask = new Subtask("Сабтаска", "Описание", Status.NEW, epic.getId());
+ taskManager.addSubtask(subtask);
+ List subtasks = taskManager.getEpicSubtasks(epic.getId());
+ assertFalse(subtasks.isEmpty(), "Сабтаска должна быть добавлена к эпику");
+ assertEquals(subtask, subtasks.get(0), "Сабтаска должна быть корректно связана с эпиком");
+ }
+
+ @Test
+ public void testSubtaskRequiresValidEpic() {
+ Subtask subtask = new Subtask("Сабтаска", "Описание", Status.NEW, 999); // Несуществующий ID у Эпика
+ assertThrows(IllegalArgumentException.class, () -> {
+ taskManager.addSubtask(subtask);
+ }, "Добавление подзадачи с несуществующим ID эпика");
+ }
+
+ @Test
+ public void testEpicStatusCalculation() {
+ Epic epic = new Epic("Эпик", "Описание", Status.NEW);
+ taskManager.addEpic(epic);
+
+ Subtask subtask1 = new Subtask("Сабтаска1", "Описание", Status.NEW, epic.getId());
+ Subtask subtask2 = new Subtask("Сабтаска2", "Описание", Status.NEW, epic.getId());
+ taskManager.addSubtask(subtask1);
+ taskManager.addSubtask(subtask2);
+ Epic updatedEpic = getEpicById(epic.getId());
+ assertEquals(Status.NEW, updatedEpic.getStatus(), "Статус должен быть NEW, если все подзадачи NEW");
+
+ subtask1.setStatus(Status.DONE);
+ subtask2.setStatus(Status.DONE);
+ taskManager.updateSubtask(subtask1);
+ taskManager.updateSubtask(subtask2);
+ updatedEpic = getEpicById(epic.getId());
+ assertEquals(Status.DONE, updatedEpic.getStatus(), "Статус должен быть DONE, если все подзадачи DONE");
+
+ subtask1.setStatus(Status.NEW);
+ taskManager.updateSubtask(subtask1);
+ updatedEpic = getEpicById(epic.getId());
+ assertEquals(Status.IN_PROGRESS, updatedEpic.getStatus(), "Статус должен быть IN_PROGRESS, если статусы NEW и DONE");
+
+ subtask2.setStatus(Status.IN_PROGRESS);
+ taskManager.updateSubtask(subtask2);
+ updatedEpic = getEpicById(epic.getId());
+ assertEquals(Status.IN_PROGRESS, updatedEpic.getStatus(), "Статус олжен быть IN_PROGRESS, если есть подзадача IN_PROGRESS");
+ }
+
+ @Test
+ public void testTaskIntervalOverlap() {
+ baseTime = LocalDateTime.of(2025, 4, 1, 10, 0);
+ Task task1 = new Task("Таск1", "Описание", Status.NEW, Duration.ofMinutes(60), baseTime);
+ Task task2 = new Task("Таск2", "Описание", Status.NEW, Duration.ofMinutes(60), baseTime.plusMinutes(30));
+ taskManager.addTask(task1);
+ assertThrows(IllegalArgumentException.class, () -> {
+ taskManager.addTask(task2);
+ }, "Добавление задачи с пересекающимся временным интервалом должно вызывать исключение");
+ }
+
+ private Epic getEpicById(int id) {
+ return taskManager.getAllEpic().stream()
+ .filter(epic -> epic.getId() == id)
+ .findFirst()
+ .orElse(null);
+ }
+}
\ No newline at end of file
diff --git a/test_tasks.csv b/test_tasks.csv
new file mode 100644
index 0000000..dbaf265
--- /dev/null
+++ b/test_tasks.csv
@@ -0,0 +1,2 @@
+id,type,name,status,description,StartTime,duration,epic
+0,EPIC,Epic,NEW,Description,null,0,