diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..54b5b20
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..aa00ffa
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
new file mode 100644
index 0000000..712ab9d
--- /dev/null
+++ b/.idea/jarRepositories.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index a9182a4..f88aef9 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,5 +1,13 @@
+
+
+
+
diff --git a/java-kanban.iml b/java-kanban.iml
index 66c15d2..048fe69 100644
--- a/java-kanban.iml
+++ b/java-kanban.iml
@@ -1,28 +1,9 @@
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..4366965
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,50 @@
+
+
+ 4.0.0
+
+ ru.yandex.practicum
+ java-kanban
+ 1.0-SNAPSHOT
+
+
+ 11
+ 11
+ UTF-8
+
+
+
+
+ com.google.code.gson
+ gson
+ 2.10.1
+
+
+ org.junit.jupiter
+ junit-jupiter
+ 5.9.2
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.11.0
+
+ 11
+ 11
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.0.0
+
+
+
+
\ No newline at end of file
diff --git a/src/http/BaseHttpHandler.java b/src/http/BaseHttpHandler.java
new file mode 100644
index 0000000..57988a9
--- /dev/null
+++ b/src/http/BaseHttpHandler.java
@@ -0,0 +1,62 @@
+package http;
+
+import com.sun.net.httpserver.HttpExchange;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+public class BaseHttpHandler {
+
+ protected void sendText(HttpExchange exchange, String text) throws IOException {
+ byte[] response = text.getBytes(StandardCharsets.UTF_8);
+ exchange.getResponseHeaders().add("Content-Type", "application/json;charset=utf-8");
+ exchange.sendResponseHeaders(200, response.length);
+ exchange.getResponseBody().write(response);
+ exchange.close();
+ }
+
+ protected void sendSuccess(HttpExchange exchange) throws IOException {
+ exchange.getResponseHeaders().add("Content-Type", "application/json;charset=utf-8");
+ exchange.sendResponseHeaders(201, -1);
+ exchange.close();
+ }
+
+ protected void sendNotFound(HttpExchange exchange) throws IOException {
+ String response = String.format("{\"error\": \"%s\"}", "Объект не найден");
+ byte[] bytes = response.getBytes(StandardCharsets.UTF_8);
+ exchange.getResponseHeaders().add("Content-Type", "application/json;charset=utf-8");
+ exchange.sendResponseHeaders(404, bytes.length);
+ exchange.getResponseBody().write(bytes);
+ exchange.close();
+ }
+
+ protected void sendHasInteractions(HttpExchange exchange) throws IOException {
+ String response = String.format("{\"error\": \"%s\"}", "Задача пересекается с существующими");
+ byte[] bytes = response.getBytes(StandardCharsets.UTF_8);
+ exchange.getResponseHeaders().add("Content-Type", "application/json;charset=utf-8");
+ exchange.sendResponseHeaders(406, bytes.length);
+ exchange.getResponseBody().write(bytes);
+ exchange.close();
+ }
+
+ protected void sendInternalError(HttpExchange exchange) throws IOException {
+ String response = String.format("{\"error\": \"%s\"}", "Внутренняя ошибка сервера");
+ byte[] bytes = response.getBytes(StandardCharsets.UTF_8);
+ exchange.getResponseHeaders().add("Content-Type", "application/json;charset=utf-8");
+ exchange.sendResponseHeaders(500, bytes.length);
+ exchange.getResponseBody().write(bytes);
+ exchange.close();
+ }
+
+ protected void sendBadRequest(HttpExchange exchange, String message) throws IOException {
+ String response = String.format("{\"error\": \"%s\"}", message);
+ byte[] bytes = response.getBytes(StandardCharsets.UTF_8);
+ exchange.getResponseHeaders().add("Content-Type", "application/json;charset=utf-8");
+ exchange.sendResponseHeaders(400, bytes.length);
+ exchange.getResponseBody().write(bytes);
+ exchange.close();
+ }
+
+ protected String readRequestBody(HttpExchange exchange) throws IOException {
+ return new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8);
+ }
+}
\ No newline at end of file
diff --git a/src/http/EpicsHandler.java b/src/http/EpicsHandler.java
new file mode 100644
index 0000000..e7827a0
--- /dev/null
+++ b/src/http/EpicsHandler.java
@@ -0,0 +1,116 @@
+package http;
+
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import manager.TaskManager;
+import model.Epic;
+import model.Subtask;
+import java.io.IOException;
+import java.util.List;
+
+public class EpicsHandler extends BaseHttpHandler implements HttpHandler {
+ private final TaskManager taskManager;
+
+ public EpicsHandler(TaskManager taskManager) {
+ this.taskManager = taskManager;
+ }
+
+ @Override
+ public void handle(HttpExchange exchange) throws IOException {
+ try {
+ String method = exchange.getRequestMethod();
+ String path = exchange.getRequestURI().getPath();
+
+ switch (method) {
+ case "GET":
+ handleGet(exchange, path);
+ break;
+ case "POST":
+ handlePost(exchange);
+ break;
+ case "DELETE":
+ handleDelete(exchange, path);
+ break;
+ default:
+ sendBadRequest(exchange, "Метод не поддерживается");
+ }
+ } catch (Exception e) {
+ sendInternalError(exchange);
+ }
+ }
+
+ private void handleGet(HttpExchange exchange, String path) throws IOException {
+ if (path.equals("/epics")) {
+ List epics = taskManager.getAllEpics();
+ String response = JsonConverter.epicsToJson(epics);
+ sendText(exchange, response);
+ } else if (path.matches("/epics/\\d+")) {
+ String[] pathParts = path.split("/");
+ int id = Integer.parseInt(pathParts[2]);
+
+ Epic epic = taskManager.getEpicById(id);
+ if (epic != null) {
+ String response = JsonConverter.epicToJson(epic);
+ sendText(exchange, response);
+ } else {
+ sendNotFound(exchange);
+ }
+ } else if (path.matches("/epics/\\d+/subtasks")) {
+ String[] pathParts = path.split("/");
+ int epicId = Integer.parseInt(pathParts[2]);
+
+ Epic epic = taskManager.getEpicById(epicId);
+ if (epic != null) {
+ List subtasks = taskManager.getSubtasksByEpicId(epicId);
+ String response = JsonConverter.subtasksToJson(subtasks);
+ sendText(exchange, response);
+ } else {
+ sendNotFound(exchange);
+ }
+ } else {
+ sendNotFound(exchange);
+ }
+ }
+
+ private void handlePost(HttpExchange exchange) throws IOException {
+ String body = readRequestBody(exchange);
+ Epic epic = JsonConverter.epicFromJson(body);
+
+ if (epic == null) {
+ sendBadRequest(exchange, "Неверный формат эпика");
+ return;
+ }
+
+ if (epic.getId() == 0) {
+ Epic created = taskManager.createEpic(epic);
+ if (created != null) {
+ sendSuccess(exchange);
+ } else {
+ sendInternalError(exchange);
+ }
+ } else {
+ taskManager.updateEpic(epic);
+ sendSuccess(exchange);
+ }
+ }
+
+ private void handleDelete(HttpExchange exchange, String path) throws IOException {
+ if (path.equals("/epics")) {
+ taskManager.deleteAllEpics();
+ sendSuccess(exchange);
+ } else if (path.matches("/epics/\\d+")) {
+ String[] pathParts = path.split("/");
+ int id = Integer.parseInt(pathParts[2]);
+
+ Epic epic = taskManager.getEpicById(id);
+ if (epic != null) {
+ taskManager.deleteEpicById(id);
+ sendSuccess(exchange);
+ } else {
+ sendNotFound(exchange);
+ }
+ } else {
+ sendNotFound(exchange);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/http/HistoryHandler.java b/src/http/HistoryHandler.java
new file mode 100644
index 0000000..7c52c6d
--- /dev/null
+++ b/src/http/HistoryHandler.java
@@ -0,0 +1,31 @@
+package http;
+
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import manager.TaskManager;
+import model.Task;
+import java.io.IOException;
+import java.util.List;
+
+public class HistoryHandler extends BaseHttpHandler implements HttpHandler {
+ private final TaskManager taskManager;
+
+ public HistoryHandler(TaskManager taskManager) {
+ this.taskManager = taskManager;
+ }
+
+ @Override
+ public void handle(HttpExchange exchange) throws IOException {
+ try {
+ if ("GET".equals(exchange.getRequestMethod())) {
+ List history = taskManager.getHistory();
+ String response = JsonConverter.tasksToJson(history);
+ sendText(exchange, response);
+ } else {
+ sendBadRequest(exchange, "Метод не поддерживается");
+ }
+ } catch (Exception e) {
+ sendInternalError(exchange);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/http/HttpTaskServer.java b/src/http/HttpTaskServer.java
new file mode 100644
index 0000000..0bff963
--- /dev/null
+++ b/src/http/HttpTaskServer.java
@@ -0,0 +1,52 @@
+package http;
+
+import com.sun.net.httpserver.HttpServer;
+import manager.TaskManager;
+import manager.Managers;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
+public class HttpTaskServer {
+ private static final int PORT = 8080;
+ private final TaskManager taskManager;
+ private HttpServer server;
+
+ public HttpTaskServer(TaskManager taskManager) {
+ this.taskManager = taskManager;
+ }
+
+ public void start() {
+ try {
+ server = HttpServer.create(new InetSocketAddress(PORT), 0);
+
+ // Регистрируем обработчики
+ server.createContext("/tasks", new TasksHandler(taskManager));
+ server.createContext("/epics", new EpicsHandler(taskManager));
+ server.createContext("/subtasks", new SubtasksHandler(taskManager));
+ server.createContext("/history", new HistoryHandler(taskManager));
+ server.createContext("/prioritized", new PrioritizedHandler(taskManager));
+
+ server.start();
+ System.out.println(String.format("HTTP Task Server запущен на порту %d", PORT));
+ System.out.println(String.format("Доступные эндпоинты: /tasks, /epics, /subtasks, /history, /prioritized"));
+ } catch (IOException exception) {
+ throw new RuntimeException(String.format("Не удалось запустить HTTP сервер на порту %d", PORT), exception);
+ }
+ }
+
+ public void stop() {
+ if (server != null) {
+ server.stop(0);
+ System.out.println(String.format("HTTP Task Server остановлен"));
+ }
+ }
+
+ public static void main(String[] arguments) {
+ TaskManager manager = Managers.getDefault();
+ HttpTaskServer server = new HttpTaskServer(manager);
+ server.start();
+
+ // Добавляем shutdown hook для graceful shutdown
+ Runtime.getRuntime().addShutdownHook(new Thread(server::stop));
+ }
+}
\ No newline at end of file
diff --git a/src/http/JsonConverter.java b/src/http/JsonConverter.java
new file mode 100644
index 0000000..fefd1f5
--- /dev/null
+++ b/src/http/JsonConverter.java
@@ -0,0 +1,349 @@
+package http;
+
+import model.Task;
+import model.Epic;
+import model.Subtask;
+import model.Status;
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.util.List;
+
+public class JsonConverter {
+
+ public static String taskToJson(Task task) {
+ if (task == null) return "null";
+
+ StringBuilder jsonBuilder = new StringBuilder();
+ jsonBuilder.append("{");
+ jsonBuilder.append("\"id\":").append(task.getId()).append(",");
+ jsonBuilder.append("\"name\":\"").append(escapeJson(task.getName())).append("\",");
+ jsonBuilder.append("\"description\":\"").append(escapeJson(task.getDescription())).append("\",");
+ jsonBuilder.append("\"status\":\"").append(task.getStatus()).append("\",");
+ jsonBuilder.append("\"type\":\"TASK\",");
+
+ if (task.getDuration() != null) {
+ jsonBuilder.append("\"duration\":").append(task.getDuration().toMinutes()).append(",");
+ } else {
+ jsonBuilder.append("\"duration\":0,");
+ }
+
+ if (task.getStartTime() != null) {
+ jsonBuilder.append("\"startTime\":\"").append(task.getStartTime()).append("\"");
+ } else {
+ jsonBuilder.append("\"startTime\":null");
+ }
+
+ jsonBuilder.append("}");
+ return jsonBuilder.toString();
+ }
+
+ public static String epicToJson(Epic epic) {
+ if (epic == null) return "null";
+
+ StringBuilder jsonBuilder = new StringBuilder();
+ jsonBuilder.append("{");
+ jsonBuilder.append("\"id\":").append(epic.getId()).append(",");
+ jsonBuilder.append("\"name\":\"").append(escapeJson(epic.getName())).append("\",");
+ jsonBuilder.append("\"description\":\"").append(escapeJson(epic.getDescription())).append("\",");
+ jsonBuilder.append("\"status\":\"").append(epic.getStatus()).append("\",");
+ jsonBuilder.append("\"type\":\"EPIC\",");
+
+ if (epic.getDuration() != null) {
+ jsonBuilder.append("\"duration\":").append(epic.getDuration().toMinutes()).append(",");
+ } else {
+ jsonBuilder.append("\"duration\":0,");
+ }
+
+ if (epic.getStartTime() != null) {
+ jsonBuilder.append("\"startTime\":\"").append(epic.getStartTime()).append("\",");
+ } else {
+ jsonBuilder.append("\"startTime\":null,");
+ }
+
+ if (epic.getEndTime() != null) {
+ jsonBuilder.append("\"endTime\":\"").append(epic.getEndTime()).append("\",");
+ } else {
+ jsonBuilder.append("\"endTime\":null,");
+ }
+
+ jsonBuilder.append("\"subtaskIds\":").append(epic.getSubtaskIds().toString());
+ jsonBuilder.append("}");
+ return jsonBuilder.toString();
+ }
+
+ public static String subtaskToJson(Subtask subtask) {
+ if (subtask == null) return "null";
+
+ StringBuilder jsonBuilder = new StringBuilder();
+ jsonBuilder.append("{");
+ jsonBuilder.append("\"id\":").append(subtask.getId()).append(",");
+ jsonBuilder.append("\"name\":\"").append(escapeJson(subtask.getName())).append("\",");
+ jsonBuilder.append("\"description\":\"").append(escapeJson(subtask.getDescription())).append("\",");
+ jsonBuilder.append("\"status\":\"").append(subtask.getStatus()).append("\",");
+ jsonBuilder.append("\"type\":\"SUBTASK\",");
+ jsonBuilder.append("\"epicId\":").append(subtask.getEpicId()).append(",");
+
+ if (subtask.getDuration() != null) {
+ jsonBuilder.append("\"duration\":").append(subtask.getDuration().toMinutes()).append(",");
+ } else {
+ jsonBuilder.append("\"duration\":0,");
+ }
+
+ if (subtask.getStartTime() != null) {
+ jsonBuilder.append("\"startTime\":\"").append(subtask.getStartTime()).append("\"");
+ } else {
+ jsonBuilder.append("\"startTime\":null");
+ }
+
+ jsonBuilder.append("}");
+ return jsonBuilder.toString();
+ }
+
+ public static String tasksToJson(List tasks) {
+ if (tasks == null) return "[]";
+
+ StringBuilder jsonBuilder = new StringBuilder();
+ jsonBuilder.append("[");
+ for (int taskIndex = 0; taskIndex < tasks.size(); taskIndex++) {
+ jsonBuilder.append(taskToJson(tasks.get(taskIndex)));
+ if (taskIndex < tasks.size() - 1) {
+ jsonBuilder.append(",");
+ }
+ }
+ jsonBuilder.append("]");
+ return jsonBuilder.toString();
+ }
+
+ public static String epicsToJson(List epics) {
+ if (epics == null) return "[]";
+
+ StringBuilder jsonBuilder = new StringBuilder();
+ jsonBuilder.append("[");
+ for (int epicIndex = 0; epicIndex < epics.size(); epicIndex++) {
+ jsonBuilder.append(epicToJson(epics.get(epicIndex)));
+ if (epicIndex < epics.size() - 1) {
+ jsonBuilder.append(",");
+ }
+ }
+ jsonBuilder.append("]");
+ return jsonBuilder.toString();
+ }
+
+ public static String subtasksToJson(List subtasks) {
+ if (subtasks == null) return "[]";
+
+ StringBuilder jsonBuilder = new StringBuilder();
+ jsonBuilder.append("[");
+ for (int subtaskIndex = 0; subtaskIndex < subtasks.size(); subtaskIndex++) {
+ jsonBuilder.append(subtaskToJson(subtasks.get(subtaskIndex)));
+ if (subtaskIndex < subtasks.size() - 1) {
+ jsonBuilder.append(",");
+ }
+ }
+ jsonBuilder.append("]");
+ return jsonBuilder.toString();
+ }
+
+ public static Task taskFromJson(String json) {
+ try {
+ if (json == null || json.trim().isEmpty() || json.equals("null")) {
+ return null;
+ }
+
+ // Простой парсинг JSON
+ String cleanJson = json.trim().replaceAll("[{}\"]", "");
+ String[] keyValuePairs = cleanJson.split(",");
+
+ int taskId = 0;
+ String taskName = "";
+ String taskDescription = "";
+ Status taskStatus = Status.NEW;
+ Duration taskDuration = Duration.ZERO;
+ LocalDateTime taskStartTime = null;
+
+ for (String keyValuePair : keyValuePairs) {
+ String[] keyValue = keyValuePair.split(":", 2);
+ if (keyValue.length != 2) continue;
+
+ String key = keyValue[0].trim();
+ String value = keyValue[1].trim();
+
+ switch (key) {
+ case "id":
+ taskId = Integer.parseInt(value);
+ break;
+ case "name":
+ taskName = unescapeJson(value);
+ break;
+ case "description":
+ taskDescription = unescapeJson(value);
+ break;
+ case "status":
+ taskStatus = Status.valueOf(value);
+ break;
+ case "duration":
+ taskDuration = Duration.ofMinutes(Long.parseLong(value));
+ break;
+ case "startTime":
+ if (!value.equals("null")) {
+ taskStartTime = LocalDateTime.parse(value);
+ }
+ break;
+ }
+ }
+
+ if (taskId == 0) {
+ return new Task(taskName, taskDescription, taskStatus, taskDuration, taskStartTime);
+ } else {
+ return new Task(taskName, taskDescription, taskId, taskStatus, taskDuration, taskStartTime);
+ }
+ } catch (Exception exception) {
+ return null;
+ }
+ }
+
+ public static Epic epicFromJson(String json) {
+ try {
+ if (json == null || json.trim().isEmpty() || json.equals("null")) {
+ return null;
+ }
+
+ String cleanJson = json.trim().replaceAll("[{}\"]", "");
+ String[] keyValuePairs = cleanJson.split(",");
+
+ int epicId = 0;
+ String epicName = "";
+ String epicDescription = "";
+ Status epicStatus = Status.NEW;
+ Duration epicDuration = Duration.ZERO;
+ LocalDateTime epicStartTime = null;
+ LocalDateTime epicEndTime = null;
+
+ for (String keyValuePair : keyValuePairs) {
+ String[] keyValue = keyValuePair.split(":", 2);
+ if (keyValue.length != 2) continue;
+
+ String key = keyValue[0].trim();
+ String value = keyValue[1].trim();
+
+ switch (key) {
+ case "id":
+ epicId = Integer.parseInt(value);
+ break;
+ case "name":
+ epicName = unescapeJson(value);
+ break;
+ case "description":
+ epicDescription = unescapeJson(value);
+ break;
+ case "status":
+ epicStatus = Status.valueOf(value);
+ break;
+ case "duration":
+ epicDuration = Duration.ofMinutes(Long.parseLong(value));
+ break;
+ case "startTime":
+ if (!value.equals("null")) {
+ epicStartTime = LocalDateTime.parse(value);
+ }
+ break;
+ case "endTime":
+ if (!value.equals("null")) {
+ epicEndTime = LocalDateTime.parse(value);
+ }
+ break;
+ }
+ }
+
+ Epic epic;
+ if (epicId == 0) {
+ epic = new Epic(epicName, epicDescription);
+ } else {
+ epic = new Epic(epicName, epicDescription, epicId, epicStatus, epicDuration, epicStartTime, epicEndTime);
+ }
+
+ return epic;
+ } catch (Exception exception) {
+ return null;
+ }
+ }
+
+ public static Subtask subtaskFromJson(String json) {
+ try {
+ if (json == null || json.trim().isEmpty() || json.equals("null")) {
+ return null;
+ }
+
+ String cleanJson = json.trim().replaceAll("[{}\"]", "");
+ String[] keyValuePairs = cleanJson.split(",");
+
+ int subtaskId = 0;
+ String subtaskName = "";
+ String subtaskDescription = "";
+ Status subtaskStatus = Status.NEW;
+ int subtaskEpicId = 0;
+ Duration subtaskDuration = Duration.ZERO;
+ LocalDateTime subtaskStartTime = null;
+
+ for (String keyValuePair : keyValuePairs) {
+ String[] keyValue = keyValuePair.split(":", 2);
+ if (keyValue.length != 2) continue;
+
+ String key = keyValue[0].trim();
+ String value = keyValue[1].trim();
+
+ switch (key) {
+ case "id":
+ subtaskId = Integer.parseInt(value);
+ break;
+ case "name":
+ subtaskName = unescapeJson(value);
+ break;
+ case "description":
+ subtaskDescription = unescapeJson(value);
+ break;
+ case "status":
+ subtaskStatus = Status.valueOf(value);
+ break;
+ case "epicId":
+ subtaskEpicId = Integer.parseInt(value);
+ break;
+ case "duration":
+ subtaskDuration = Duration.ofMinutes(Long.parseLong(value));
+ break;
+ case "startTime":
+ if (!value.equals("null")) {
+ subtaskStartTime = LocalDateTime.parse(value);
+ }
+ break;
+ }
+ }
+
+ if (subtaskId == 0) {
+ return new Subtask(subtaskName, subtaskDescription, subtaskStatus, subtaskEpicId, subtaskDuration, subtaskStartTime);
+ } else {
+ return new Subtask(subtaskName, subtaskDescription, subtaskId, subtaskStatus, subtaskEpicId, subtaskDuration, subtaskStartTime);
+ }
+ } catch (Exception exception) {
+ return null;
+ }
+ }
+
+ private static String escapeJson(String inputString) {
+ if (inputString == null) return "";
+ return inputString.replace("\\", "\\\\")
+ .replace("\"", "\\\"")
+ .replace("\n", "\\n")
+ .replace("\r", "\\r")
+ .replace("\t", "\\t");
+ }
+
+ private static String unescapeJson(String inputString) {
+ if (inputString == null) return "";
+ return inputString.replace("\\\"", "\"")
+ .replace("\\\\", "\\")
+ .replace("\\n", "\n")
+ .replace("\\r", "\r")
+ .replace("\\t", "\t");
+ }
+}
\ No newline at end of file
diff --git a/src/http/PrioritizedHandler.java b/src/http/PrioritizedHandler.java
new file mode 100644
index 0000000..158a5b4
--- /dev/null
+++ b/src/http/PrioritizedHandler.java
@@ -0,0 +1,31 @@
+package http;
+
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import manager.TaskManager;
+import model.Task;
+import java.io.IOException;
+import java.util.List;
+
+public class PrioritizedHandler extends BaseHttpHandler implements HttpHandler {
+ private final TaskManager taskManager;
+
+ public PrioritizedHandler(TaskManager taskManager) {
+ this.taskManager = taskManager;
+ }
+
+ @Override
+ public void handle(HttpExchange exchange) throws IOException {
+ try {
+ if ("GET".equals(exchange.getRequestMethod())) {
+ List prioritizedTasks = taskManager.getPrioritizedTasks();
+ String response = JsonConverter.tasksToJson(prioritizedTasks);
+ sendText(exchange, response);
+ } else {
+ sendBadRequest(exchange, "Метод не поддерживается");
+ }
+ } catch (Exception e) {
+ sendInternalError(exchange);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/http/SubtasksHandler.java b/src/http/SubtasksHandler.java
new file mode 100644
index 0000000..8c32e28
--- /dev/null
+++ b/src/http/SubtasksHandler.java
@@ -0,0 +1,107 @@
+package http;
+
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import manager.TaskManager;
+import model.Subtask;
+import java.io.IOException;
+import java.util.List;
+
+public class SubtasksHandler extends BaseHttpHandler implements HttpHandler {
+ private final TaskManager taskManager;
+
+ public SubtasksHandler(TaskManager taskManager) {
+ this.taskManager = taskManager;
+ }
+
+ @Override
+ public void handle(HttpExchange exchange) throws IOException {
+ try {
+ String method = exchange.getRequestMethod();
+ String path = exchange.getRequestURI().getPath();
+
+ switch (method) {
+ case "GET":
+ handleGet(exchange, path);
+ break;
+ case "POST":
+ handlePost(exchange);
+ break;
+ case "DELETE":
+ handleDelete(exchange, path);
+ break;
+ default:
+ sendBadRequest(exchange, "Метод не поддерживается");
+ }
+ } catch (Exception e) {
+ sendInternalError(exchange);
+ }
+ }
+
+ private void handleGet(HttpExchange exchange, String path) throws IOException {
+ if (path.equals("/subtasks")) {
+ List subtasks = taskManager.getAllSubtasks();
+ String response = JsonConverter.subtasksToJson(subtasks);
+ sendText(exchange, response);
+ } else if (path.matches("/subtasks/\\d+")) {
+ String[] pathParts = path.split("/");
+ int id = Integer.parseInt(pathParts[2]);
+
+ Subtask subtask = taskManager.getSubtaskById(id);
+ if (subtask != null) {
+ String response = JsonConverter.subtaskToJson(subtask);
+ sendText(exchange, response);
+ } else {
+ sendNotFound(exchange);
+ }
+ } else {
+ sendNotFound(exchange);
+ }
+ }
+
+ private void handlePost(HttpExchange exchange) throws IOException {
+ String body = readRequestBody(exchange);
+ Subtask subtask = JsonConverter.subtaskFromJson(body);
+
+ if (subtask == null) {
+ sendBadRequest(exchange, "Неверный формат подзадачи");
+ return;
+ }
+
+ if (subtask.getId() == 0) {
+ Subtask created = taskManager.createSubtask(subtask);
+ if (created != null) {
+ sendSuccess(exchange);
+ } else {
+ if (taskManager.isTaskOverlapping(subtask)) {
+ sendHasInteractions(exchange);
+ } else {
+ sendInternalError(exchange);
+ }
+ }
+ } else {
+ taskManager.updateSubtask(subtask);
+ sendSuccess(exchange);
+ }
+ }
+
+ private void handleDelete(HttpExchange exchange, String path) throws IOException {
+ if (path.equals("/subtasks")) {
+ taskManager.deleteAllSubtasks();
+ sendSuccess(exchange);
+ } else if (path.matches("/subtasks/\\d+")) {
+ String[] pathParts = path.split("/");
+ int id = Integer.parseInt(pathParts[2]);
+
+ Subtask subtask = taskManager.getSubtaskById(id);
+ if (subtask != null) {
+ taskManager.deleteSubtaskById(id);
+ sendSuccess(exchange);
+ } else {
+ sendNotFound(exchange);
+ }
+ } else {
+ sendNotFound(exchange);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/http/TasksHandler.java b/src/http/TasksHandler.java
new file mode 100644
index 0000000..e907428
--- /dev/null
+++ b/src/http/TasksHandler.java
@@ -0,0 +1,109 @@
+package http;
+
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import manager.TaskManager;
+import model.Task;
+import java.io.IOException;
+import java.util.List;
+
+public class TasksHandler extends BaseHttpHandler implements HttpHandler {
+ private final TaskManager taskManager;
+
+ public TasksHandler(TaskManager taskManager) {
+ this.taskManager = taskManager;
+ }
+
+ @Override
+ public void handle(HttpExchange exchange) throws IOException {
+ try {
+ String method = exchange.getRequestMethod();
+ String path = exchange.getRequestURI().getPath();
+
+ switch (method) {
+ case "GET":
+ handleGet(exchange, path);
+ break;
+ case "POST":
+ handlePost(exchange);
+ break;
+ case "DELETE":
+ handleDelete(exchange, path);
+ break;
+ default:
+ sendBadRequest(exchange, "Метод не поддерживается");
+ }
+ } catch (Exception exception) {
+ sendInternalError(exchange);
+ }
+ }
+
+ private void handleGet(HttpExchange exchange, String path) throws IOException {
+ if (path.equals("/tasks")) {
+ List tasks = taskManager.getAllTasks();
+ String response = JsonConverter.tasksToJson(tasks);
+ sendText(exchange, response);
+ } else if (path.matches("/tasks/\\d+")) {
+ String[] pathParts = path.split("/");
+ int taskId = Integer.parseInt(pathParts[2]);
+
+ Task task = taskManager.getTaskById(taskId);
+ if (task != null) {
+ String response = JsonConverter.taskToJson(task);
+ sendText(exchange, response);
+ } else {
+ sendNotFound(exchange);
+ }
+ } else {
+ sendNotFound(exchange);
+ }
+ }
+
+ private void handlePost(HttpExchange exchange) throws IOException {
+ String requestBody = readRequestBody(exchange);
+ Task task = JsonConverter.taskFromJson(requestBody);
+
+ if (task == null) {
+ sendBadRequest(exchange, "Неверный формат задачи");
+ return;
+ }
+
+ if (task.getId() == 0) {
+ // Создание новой задачи
+ Task createdTask = taskManager.createTask(task);
+ if (createdTask != null) {
+ sendSuccess(exchange);
+ } else {
+ if (taskManager.isTaskOverlapping(task)) {
+ sendHasInteractions(exchange);
+ } else {
+ sendInternalError(exchange);
+ }
+ }
+ } else {
+ // Обновление существующей задачи
+ taskManager.updateTask(task);
+ sendSuccess(exchange);
+ }
+ }
+
+ private void handleDelete(HttpExchange exchange, String path) throws IOException {
+ if (path.equals("/tasks")) {
+ taskManager.deleteAllTasks();
+ sendSuccess(exchange);
+ } else if (path.matches("/tasks/\\d+")) {
+ String[] pathParts = path.split("/");
+ int taskId = Integer.parseInt(pathParts[2]);
+
+ Task task = taskManager.getTaskById(taskId);
+ if (task != null) {
+ taskManager.deleteTaskById(taskId);
+ sendSuccess(exchange);
+ } else {
+ sendNotFound(exchange);
+ }
+ } else {
+ sendNotFound(exchange);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/manager/FileBackedTaskManager.java b/src/manager/FileBackedTaskManager.java
new file mode 100644
index 0000000..fae8d25
--- /dev/null
+++ b/src/manager/FileBackedTaskManager.java
@@ -0,0 +1,272 @@
+package manager;
+
+import model.*;
+import model.TaskType;
+
+import java.io.*;
+import java.nio.file.Files;
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+public class FileBackedTaskManager extends InMemoryTaskManager {
+ private final File file;
+ private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
+
+ public FileBackedTaskManager(File file) {
+ this.file = file;
+ }
+
+ @Override
+ public Task createTask(Task task) {
+ Task createdTask = super.createTask(task);
+ save();
+ return createdTask;
+ }
+
+ @Override
+ public Epic createEpic(Epic epic) {
+ Epic createdEpic = super.createEpic(epic);
+ save();
+ return createdEpic;
+ }
+
+ @Override
+ public Subtask createSubtask(Subtask subtask) {
+ Subtask createdSubtask = super.createSubtask(subtask);
+ save();
+ return createdSubtask;
+ }
+
+ @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 deleteTaskById(int id) {
+ super.deleteTaskById(id);
+ save();
+ }
+
+ @Override
+ public void deleteEpicById(int id) {
+ super.deleteEpicById(id);
+ save();
+ }
+
+ @Override
+ public void deleteSubtaskById(int id) {
+ super.deleteSubtaskById(id);
+ save();
+ }
+
+ @Override
+ public void deleteAllTasks() {
+ super.deleteAllTasks();
+ save();
+ }
+
+ @Override
+ public void deleteAllEpics() {
+ super.deleteAllEpics();
+ save();
+ }
+
+ @Override
+ public void deleteAllSubtasks() {
+ super.deleteAllSubtasks();
+ save();
+ }
+
+ protected void save() {
+ try (PrintWriter writer = new PrintWriter(file)) {
+ writer.println("id,type,name,status,description,epic,duration,startTime");
+
+ for (Task task : getAllTasks()) {
+ writer.println(taskToString(task));
+ }
+ for (Epic epic : getAllEpics()) {
+ writer.println(taskToString(epic));
+ }
+ for (Subtask subtask : getAllSubtasks()) {
+ writer.println(taskToString(subtask));
+ }
+ } catch (IOException e) {
+ throw new ManagerSaveException("Ошибка сохранения в файл", e);
+ }
+ }
+
+ private String taskToString(Task task) {
+ String durationStr = task.getDuration() != null
+ ? String.valueOf(task.getDuration().toMinutes()) : "";
+ String startTimeStr = task.getStartTime() != null
+ ? task.getStartTime().format(DATE_TIME_FORMATTER) : "";
+
+ if (task instanceof Epic) {
+ Epic epic = (Epic) task;
+ String endTimeStr = epic.getEndTime() != null
+ ? epic.getEndTime().format(DATE_TIME_FORMATTER) : "";
+ return String.format("%d,EPIC,%s,%s,%s,,%s,%s,%s",
+ task.getId(),
+ task.getName(),
+ task.getStatus(),
+ task.getDescription(),
+ durationStr,
+ startTimeStr,
+ endTimeStr);
+ } else if (task instanceof Subtask) {
+ Subtask subtask = (Subtask) task;
+ return String.format("%d,SUBTASK,%s,%s,%s,%d,%s,%s",
+ subtask.getId(),
+ subtask.getName(),
+ subtask.getStatus(),
+ subtask.getDescription(),
+ subtask.getEpicId(),
+ durationStr,
+ startTimeStr);
+ } else {
+ return String.format("%d,TASK,%s,%s,%s,,%s,%s",
+ task.getId(),
+ task.getName(),
+ task.getStatus(),
+ task.getDescription(),
+ durationStr,
+ startTimeStr);
+ }
+ }
+
+ private Task taskFromString(String value) {
+ String[] fields = value.split(",", -1);
+ int id = Integer.parseInt(fields[0]);
+ TaskType type = TaskType.valueOf(fields[1]);
+ String name = fields[2];
+ Status status = Status.valueOf(fields[3]);
+ String description = fields[4];
+
+ Duration duration = fields[6].isEmpty() ? Duration.ZERO
+ : Duration.ofMinutes(Long.parseLong(fields[6]));
+ LocalDateTime startTime = fields[7].isEmpty() ? null
+ : LocalDateTime.parse(fields[7], DATE_TIME_FORMATTER);
+
+ switch (type) {
+ case TASK:
+ Task task = new Task(name, description, id, status, duration, startTime);
+ return task;
+ case EPIC:
+ Epic epic = new Epic(name, description, id, status, duration, startTime, null);
+ if (fields.length > 8 && !fields[8].isEmpty()) {
+ LocalDateTime endTime = LocalDateTime.parse(fields[8], DATE_TIME_FORMATTER);
+ epic.setEndTime(endTime);
+ }
+ return epic;
+ case SUBTASK:
+ int epicId = fields[5].isEmpty() ? 0 : Integer.parseInt(fields[5]);
+ Subtask subtask = new Subtask(name, description, id, status, epicId, duration, startTime);
+ return subtask;
+ default:
+ throw new IllegalArgumentException(String.format("Неизвестный тип задачи: %s", type));
+ }
+ }
+
+ public static FileBackedTaskManager loadFromFile(File file) {
+ FileBackedTaskManager manager = new FileBackedTaskManager(file);
+
+ try {
+ if (!file.exists()) {
+ return manager;
+ }
+
+ String content = Files.readString(file.toPath());
+ String[] fileLines = content.split("\n");
+
+ for (int lineNumber = 1; lineNumber < fileLines.length; lineNumber++) {
+ String currentLine = fileLines[lineNumber].trim();
+ if (currentLine.isEmpty()) {
+ continue;
+ }
+
+ Task task = manager.taskFromString(currentLine);
+ if (task instanceof Epic) {
+ manager.epics.put(task.getId(), (Epic) task);
+ } else if (task instanceof Subtask) {
+ manager.subtasks.put(task.getId(), (Subtask) task);
+ } else {
+ manager.tasks.put(task.getId(), task);
+ }
+
+ if (task.getId() >= manager.nextId) {
+ manager.nextId = task.getId() + 1;
+ }
+
+ if (task.getStartTime() != null) {
+ manager.prioritizedTasks.add(task);
+ }
+ }
+
+ for (Subtask subtask : manager.subtasks.values()) {
+ Epic epic = manager.epics.get(subtask.getEpicId());
+ if (epic != null) {
+ epic.addSubtaskId(subtask.getId());
+ }
+ }
+
+ } catch (IOException e) {
+ throw new ManagerSaveException("Ошибка загрузки из файла", e);
+ }
+
+ return manager;
+ }
+
+ public static void main(String[] args) {
+ try {
+ File tempFile = File.createTempFile("tasks", ".csv");
+
+ FileBackedTaskManager manager1 = new FileBackedTaskManager(tempFile);
+
+ Task task1 = manager1.createTask(new Task("Task 1", "Description 1", Status.NEW,
+ Duration.ofMinutes(30), LocalDateTime.now()));
+ manager1.createTask(new Task("Task 2", "Description 2", Status.IN_PROGRESS,
+ Duration.ofHours(1), LocalDateTime.now().plusHours(2)));
+
+ Epic epic1 = manager1.createEpic(new Epic("Epic 1", "Epic description"));
+ Subtask subtask1 = manager1.createSubtask(new Subtask("Subtask 1", "Sub description",
+ Status.DONE, epic1.getId(), Duration.ofMinutes(45),
+ LocalDateTime.now().plusHours(1)));
+ manager1.createSubtask(new Subtask("Subtask 2", "Sub description 2",
+ Status.NEW, epic1.getId(), Duration.ofMinutes(15),
+ LocalDateTime.now().plusHours(3)));
+
+ manager1.getTaskById(task1.getId());
+ manager1.getEpicById(epic1.getId());
+ manager1.getSubtaskById(subtask1.getId());
+
+ FileBackedTaskManager manager2 = FileBackedTaskManager.loadFromFile(tempFile);
+
+ System.out.println(String.format("Проверка восстановления данных:"));
+ System.out.println(String.format("Задачи в manager2: %d", manager2.getAllTasks().size()));
+ System.out.println(String.format("Эпики в manager2: %d", manager2.getAllEpics().size()));
+ System.out.println(String.format("Подзадачи в manager2: %d", manager2.getAllSubtasks().size()));
+ System.out.println(String.format("История в manager2: %d", manager2.getHistory().size()));
+ System.out.println(String.format("Приоритетные задачи в manager2: %d", manager2.getPrioritizedTasks().size()));
+
+ tempFile.deleteOnExit();
+
+ } catch (IOException e) {
+ System.err.println(String.format("Ошибка при работе с файлом: %s", e.getMessage()));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/manager/HistoryManager.java b/src/manager/HistoryManager.java
index 6070997..1aa53c9 100644
--- a/src/manager/HistoryManager.java
+++ b/src/manager/HistoryManager.java
@@ -5,5 +5,8 @@
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 aee6b0d..bf7c45b 100644
--- a/src/manager/InMemoryHistoryManager.java
+++ b/src/manager/InMemoryHistoryManager.java
@@ -1,25 +1,119 @@
package manager;
import model.Task;
+import model.Epic;
+import model.Subtask;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
public class InMemoryHistoryManager implements HistoryManager {
- private static final int MAX_HISTORY_SIZE = 10;
- private final List history = new ArrayList<>();
+ private 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;
- if (history.size() >= MAX_HISTORY_SIZE) {
- history.removeFirst(); // Удаляем самый старый элемент
+ remove(task.getId());
+
+
+ Task taskCopy = copyTask(task);
+ Node newNode = linkLast(taskCopy);
+ historyMap.put(taskCopy.getId(), newNode);
+ }
+
+ private Task copyTask(Task original) {
+ if (original instanceof Epic) {
+ Epic epic = (Epic) original;
+ Epic copy = new Epic(epic.getName(), epic.getDescription());
+ copy.setId(epic.getId());
+ copy.updateStatus(epic.getStatus());
+ // Копируем список подзадач
+ for (Integer subtaskId : epic.getSubtaskIds()) {
+ copy.addSubtaskId(subtaskId);
+ }
+ return copy;
+ } else if (original instanceof Subtask) {
+ Subtask subtask = (Subtask) original;
+ return new Subtask(subtask.getName(), subtask.getDescription(),
+ subtask.getId(), subtask.getStatus(), subtask.getEpicId());
+ } else {
+ return new Task(original.getName(), original.getDescription(),
+ original.getId(), original.getStatus());
+ }
+ }
+
+
+ @Override
+ public void remove(int id) {
+ Node node = historyMap.get(id);
+ if (node != null) {
+ removeNode(node);
+ historyMap.remove(id);
}
- history.add(task);
}
@Override
public List getHistory() {
- return new ArrayList<>(history);
+ return getTasks();
+ }
+
+ private Node linkLast(Task task) {
+ Node newNode = new Node(task);
+
+ if (tail == null) {
+ head = newNode;
+ tail = newNode;
+ } else {
+ tail.next = newNode;
+ newNode.prev = tail;
+ tail = newNode;
+ }
+
+ return newNode;
+ }
+
+ private void removeNode(Node node) {
+ if (node == null) return;
+
+ 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;
+ }
+
+ node.prev = null;
+ node.next = null;
+ }
+
+ private List getTasks() {
+ List tasks = new ArrayList<>();
+ Node current = head;
+
+ while (current != null) {
+ tasks.add(current.task);
+ current = current.next;
+ }
+
+ return tasks;
}
}
\ No newline at end of file
diff --git a/src/manager/InMemoryTaskManager.java b/src/manager/InMemoryTaskManager.java
index 9b107ab..9491856 100644
--- a/src/manager/InMemoryTaskManager.java
+++ b/src/manager/InMemoryTaskManager.java
@@ -4,103 +4,264 @@
import model.Epic;
import model.Subtask;
import model.Status;
+
+import java.time.Duration;
+import java.time.LocalDateTime;
import java.util.*;
+import java.util.stream.Collectors;
+import java.util.Optional;
public class InMemoryTaskManager implements TaskManager {
- private final Map tasks = new HashMap<>();
- private final Map epics = new HashMap<>();
- private final Map subtasks = new HashMap<>();
- private final HistoryManager historyManager;
- private int nextId = 1;
+ protected final Map tasks = new HashMap<>();
+ protected final Map epics = new HashMap<>();
+ protected final Map subtasks = new HashMap<>();
+ protected final HistoryManager historyManager;
+ protected int nextId = 1;
+ protected final Set prioritizedTasks = new TreeSet<>(
+ Comparator.comparing(Task::getStartTime,
+ Comparator.nullsLast(Comparator.naturalOrder()))
+ .thenComparing(Task::getId)
+ );
public InMemoryTaskManager() {
this.historyManager = Managers.getDefaultHistory();
}
- private int generateId() { return nextId++; }
+ protected int generateId() {
+ return nextId++;
+ }
- // Модифицируем методы получения задач для добавления в историю
@Override
- public Task getTaskById(int id) {
+ public Optional getTaskByIdOptional(int id) {
Task task = tasks.get(id);
if (task != null) {
historyManager.add(task);
+ return Optional.of(createTaskCopy(task));
}
- return task;
+ return Optional.empty();
}
@Override
- public Epic getEpicById(int id) {
+ public Optional getEpicByIdOptional(int id) {
Epic epic = epics.get(id);
if (epic != null) {
historyManager.add(epic);
+ return Optional.of(createEpicCopy(epic));
}
- return epic;
+ return Optional.empty();
}
@Override
- public Subtask getSubtaskById(int id) {
+ public Optional getSubtaskByIdOptional(int id) {
Subtask subtask = subtasks.get(id);
if (subtask != null) {
historyManager.add(subtask);
+ return Optional.of(createSubtaskCopy(subtask));
}
- return subtask;
+ return Optional.empty();
}
- // Добавляем метод для получения истории
@Override
- public List getHistory() {
- return historyManager.getHistory();
+ public boolean isTasksOverlapping(Task task1, Task task2) {
+ if (task1.getStartTime() == null || task2.getStartTime() == null
+ || task1.getEndTime() == null || task2.getEndTime() == null) {
+ return false;
+ }
+
+ return !task1.getEndTime().isBefore(task2.getStartTime())
+ && !task1.getStartTime().isAfter(task2.getEndTime());
}
- // Остальные методы остаются без изменений...
- @Override public List getAllTasks() { return new ArrayList<>(tasks.values()); }
+ @Override
+ public boolean hasAnyTimeOverlaps() {
+ List prioritized = getPrioritizedTasks();
+
+ for (int i = 1; i < prioritized.size(); i++) {
+ Task current = prioritized.get(i);
+ Task previous = prioritized.get(i - 1);
+
+ if (isTasksOverlapping(previous, current)) {
+ return true;
+ }
+ }
+ return false;
+ }
@Override
- public void deleteAllTasks() { tasks.clear(); }
+ public boolean isTaskOverlapping(Task task) {
+ if (task.getStartTime() == null) {
+ return false;
+ }
+
+ LocalDateTime taskStart = task.getStartTime();
+ LocalDateTime taskEnd = task.getEndTime();
+
+ if (taskEnd == null) {
+ return false;
+ }
+
+ return prioritizedTasks.stream()
+ .filter(t -> t.getStartTime() != null && t.getEndTime() != null)
+ .filter(t -> t.getId() != task.getId())
+ .anyMatch(existingTask -> isTasksOverlapping(task, existingTask));
+ }
+
+ @Override
+ public List getSubtasksByEpicId(int epicId) {
+ Epic epic = epics.get(epicId);
+ if (epic == null) {
+ return Collections.emptyList();
+ }
+
+ return epic.getSubtaskIds().stream()
+ .map(subtasks::get)
+ .filter(Objects::nonNull)
+ .map(this::createSubtaskCopy)
+ .collect(Collectors.toList());
+ }
+
+ private Task createTaskCopy(Task original) {
+ return new Task(original.getName(), original.getDescription(),
+ original.getId(), original.getStatus(),
+ original.getDuration(), original.getStartTime());
+ }
+
+ private Epic createEpicCopy(Epic original) {
+ Epic copy = new Epic(original.getName(), original.getDescription(),
+ original.getId(), original.getStatus(),
+ original.getDuration(), original.getStartTime(), original.getEndTime());
+ for (Integer subtaskId : original.getSubtaskIds()) {
+ copy.addSubtaskId(subtaskId);
+ }
+ return copy;
+ }
+
+ private Subtask createSubtaskCopy(Subtask original) {
+ return new Subtask(original.getName(), original.getDescription(),
+ original.getId(), original.getStatus(), original.getEpicId(),
+ original.getDuration(), original.getStartTime());
+ }
+
+ @Override
+ public List getAllTasks() {
+ return tasks.values().stream()
+ .map(this::createTaskCopy)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public void deleteAllTasks() {
+ for (Integer taskId : tasks.keySet()) {
+ historyManager.remove(taskId);
+ prioritizedTasks.removeIf(task -> task.getId() == taskId);
+ }
+ tasks.clear();
+ }
+
+ @Override
+ public Task getTaskById(int id) {
+ return getTaskByIdOptional(id).orElse(null);
+ }
@Override
public Task createTask(Task task) {
- if (task == null) return null;
- Task newTask = new Task(task.getName(), task.getDescription(), generateId(), task.getStatus());
+ if (task == null) {
+ return null;
+ }
+
+ if (isTaskOverlapping(task)) {
+ return null;
+ }
+
+ Task newTask = new Task(task.getName(), task.getDescription(),
+ generateId(), task.getStatus(),
+ task.getDuration(), task.getStartTime());
tasks.put(newTask.getId(), newTask);
- return newTask;
+
+ if (newTask.getStartTime() != null) {
+ prioritizedTasks.add(newTask);
+ }
+
+ return createTaskCopy(newTask);
}
@Override
public void updateTask(Task task) {
- if (task == null || !tasks.containsKey(task.getId())) return;
+ if (task == null || !tasks.containsKey(task.getId())) {
+ return;
+ }
+
+ Task existingTask = tasks.get(task.getId());
+ prioritizedTasks.remove(existingTask);
+
+ if (isTaskOverlapping(task)) {
+ prioritizedTasks.add(existingTask);
+ return;
+ }
+
tasks.put(task.getId(), task);
+
+ if (task.getStartTime() != null) {
+ prioritizedTasks.add(task);
+ }
}
@Override
- public void deleteTaskById(int id) { tasks.remove(id); }
+ public void deleteTaskById(int id) {
+ Task task = tasks.remove(id);
+ if (task != null) {
+ historyManager.remove(id);
+ prioritizedTasks.remove(task);
+ }
+ }
@Override
- public List getAllEpics() { return new ArrayList<>(epics.values()); }
+ public List getAllEpics() {
+ return epics.values().stream()
+ .map(this::createEpicCopy)
+ .collect(Collectors.toList());
+ }
@Override
public void deleteAllEpics() {
+ for (Integer epicId : epics.keySet()) {
+ historyManager.remove(epicId);
+ }
+ for (Integer subtaskId : subtasks.keySet()) {
+ historyManager.remove(subtaskId);
+ prioritizedTasks.removeIf(task -> task.getId() == subtaskId);
+ }
+
for (Epic epic : epics.values()) {
for (Integer subtaskId : epic.getSubtaskIds()) {
subtasks.remove(subtaskId);
}
}
epics.clear();
+ subtasks.clear();
+ }
+
+ @Override
+ public Epic getEpicById(int id) {
+ return getEpicByIdOptional(id).orElse(null);
}
@Override
public Epic createEpic(Epic epic) {
- if (epic == null) return null;
+ if (epic == null) {
+ return null;
+ }
Epic newEpic = new Epic(epic.getName(), epic.getDescription());
newEpic.setId(generateId());
epics.put(newEpic.getId(), newEpic);
- return newEpic;
+ return createEpicCopy(newEpic);
}
@Override
public void updateEpic(Epic epic) {
- if (epic == null || !epics.containsKey(epic.getId())) return;
+ if (epic == null || !epics.containsKey(epic.getId())) {
+ return;
+ }
Epic existingEpic = epics.get(epic.getId());
existingEpic.setName(epic.getName());
existingEpic.setDescription(epic.getDescription());
@@ -110,40 +271,101 @@ public void updateEpic(Epic epic) {
public void deleteEpicById(int id) {
Epic epic = epics.get(id);
if (epic != null) {
+ historyManager.remove(id);
for (Integer subtaskId : epic.getSubtaskIds()) {
subtasks.remove(subtaskId);
+ historyManager.remove(subtaskId);
+ prioritizedTasks.removeIf(task -> task.getId() == subtaskId);
}
epics.remove(id);
}
}
@Override
- public List getAllSubtasks() { return new ArrayList<>(subtasks.values()); }
+ public List getAllSubtasks() {
+ return subtasks.values().stream()
+ .map(this::createSubtaskCopy)
+ .collect(Collectors.toList());
+ }
@Override
public void deleteAllSubtasks() {
+ for (Integer subtaskId : subtasks.keySet()) {
+ historyManager.remove(subtaskId);
+ prioritizedTasks.removeIf(task -> task.getId() == subtaskId);
+ }
+
for (Epic epic : epics.values()) {
epic.clearSubtasks();
updateEpicStatus(epic.getId());
+ updateEpicTiming(epic.getId());
}
subtasks.clear();
}
+ @Override
+ public Subtask getSubtaskById(int id) {
+ return getSubtaskByIdOptional(id).orElse(null);
+ }
+
@Override
public Subtask createSubtask(Subtask subtask) {
- if (subtask == null || !epics.containsKey(subtask.getEpicId())) return null;
- Subtask newSubtask = new Subtask(subtask.getName(), subtask.getDescription(), generateId(), subtask.getStatus(), subtask.getEpicId());
+ if (subtask == null || !epics.containsKey(subtask.getEpicId())) {
+ return null;
+ }
+
+ Epic epic = epics.get(subtask.getEpicId());
+
+ if (subtask.getId() != 0) {
+ if (subtask.getEpicId() == subtask.getId()) {
+ return null;
+ }
+ if (epic.getId() == subtask.getId()) {
+ return null;
+ }
+ }
+
+ if (isTaskOverlapping(subtask)) {
+ return null;
+ }
+
+ Subtask newSubtask = new Subtask(subtask.getName(), subtask.getDescription(),
+ generateId(), subtask.getStatus(), subtask.getEpicId(),
+ subtask.getDuration(), subtask.getStartTime());
subtasks.put(newSubtask.getId(), newSubtask);
- Epic epic = epics.get(newSubtask.getEpicId());
epic.addSubtaskId(newSubtask.getId());
+
+ if (newSubtask.getStartTime() != null) {
+ prioritizedTasks.add(newSubtask);
+ }
+
updateEpicStatus(epic.getId());
- return newSubtask;
+ updateEpicTiming(epic.getId());
+ return createSubtaskCopy(newSubtask);
}
@Override
public void updateSubtask(Subtask subtask) {
- if (subtask == null || !subtasks.containsKey(subtask.getId())) return;
+ if (subtask == null || !subtasks.containsKey(subtask.getId())) {
+ return;
+ }
+
+ if (subtask.getEpicId() == subtask.getId()) {
+ return;
+ }
+
+ if (!epics.containsKey(subtask.getEpicId())) {
+ return;
+ }
+
Subtask existingSubtask = subtasks.get(subtask.getId());
+ prioritizedTasks.remove(existingSubtask);
+
+ if (isTaskOverlapping(subtask)) {
+ prioritizedTasks.add(existingSubtask);
+ return;
+ }
+
int oldEpicId = existingSubtask.getEpicId();
int newEpicId = subtask.getEpicId();
@@ -152,6 +374,7 @@ public void updateSubtask(Subtask subtask) {
if (oldEpic != null) {
oldEpic.removeSubtaskId(subtask.getId());
updateEpicStatus(oldEpicId);
+ updateEpicTiming(oldEpicId);
}
Epic newEpic = epics.get(newEpicId);
if (newEpic != null) {
@@ -159,8 +382,19 @@ public void updateSubtask(Subtask subtask) {
}
}
- subtasks.put(subtask.getId(), subtask);
+ existingSubtask.setName(subtask.getName());
+ existingSubtask.setDescription(subtask.getDescription());
+ existingSubtask.setStatus(subtask.getStatus());
+ existingSubtask.setEpicId(subtask.getEpicId());
+ existingSubtask.setDuration(subtask.getDuration());
+ existingSubtask.setStartTime(subtask.getStartTime());
+
+ if (existingSubtask.getStartTime() != null) {
+ prioritizedTasks.add(existingSubtask);
+ }
+
updateEpicStatus(subtask.getEpicId());
+ updateEpicTiming(subtask.getEpicId());
}
@Override
@@ -171,43 +405,96 @@ public void deleteSubtaskById(int id) {
if (epic != null) {
epic.removeSubtaskId(id);
updateEpicStatus(epic.getId());
+ updateEpicTiming(epic.getId());
}
subtasks.remove(id);
+ historyManager.remove(id);
+ prioritizedTasks.remove(subtask);
}
}
@Override
- public List getSubtasksByEpicId(int epicId) {
- List result = new ArrayList<>();
- Epic epic = epics.get(epicId);
- if (epic != null) {
- for (Integer subtaskId : epic.getSubtaskIds()) {
- Subtask subtask = subtasks.get(subtaskId);
- if (subtask != null) result.add(subtask);
- }
- }
- return result;
+ public List getHistory() {
+ return historyManager.getHistory();
+ }
+
+ @Override
+ public List getPrioritizedTasks() {
+ return new ArrayList<>(prioritizedTasks);
}
private void updateEpicStatus(int epicId) {
Epic epic = epics.get(epicId);
- if (epic == null) return;
+ if (epic == null) {
+ return;
+ }
List subtaskIds = epic.getSubtaskIds();
if (subtaskIds.isEmpty()) {
epic.updateStatus(Status.NEW);
return;
}
+
boolean allDone = true;
boolean allNew = true;
+
for (Integer subtaskId : subtaskIds) {
Subtask subtask = subtasks.get(subtaskId);
- if (subtask == null) continue;
- if (subtask.getStatus() != Status.DONE) allDone = false;
- if (subtask.getStatus() != Status.NEW) allNew = false;
- if (!allDone && !allNew) break;
- }
- if (allDone) epic.updateStatus(Status.DONE);
- else if (allNew) epic.updateStatus(Status.NEW);
- else epic.updateStatus(Status.IN_PROGRESS);
+ if (subtask == null) {
+ continue;
+ }
+ if (subtask.getStatus() != Status.DONE) {
+ allDone = false;
+ }
+ if (subtask.getStatus() != Status.NEW) {
+ allNew = false;
+ }
+ }
+
+ if (allDone) {
+ epic.updateStatus(Status.DONE);
+ } else if (allNew) {
+ epic.updateStatus(Status.NEW);
+ } else {
+ epic.updateStatus(Status.IN_PROGRESS);
+ }
+ }
+
+ private void updateEpicTiming(int epicId) {
+ Epic epic = epics.get(epicId);
+ if (epic == null) {
+ return;
+ }
+
+ List epicSubtasks = getSubtasksByEpicId(epicId).stream()
+ .map(subtask -> subtasks.get(subtask.getId()))
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+
+ if (epicSubtasks.isEmpty()) {
+ epic.setDuration(Duration.ZERO);
+ epic.setStartTime(null);
+ epic.setEndTime(null);
+ return;
+ }
+
+ Duration totalDuration = epicSubtasks.stream()
+ .map(Subtask::getDuration)
+ .filter(Objects::nonNull)
+ .reduce(Duration.ZERO, Duration::plus);
+ epic.setDuration(totalDuration);
+
+ LocalDateTime earliestStart = epicSubtasks.stream()
+ .map(Subtask::getStartTime)
+ .filter(Objects::nonNull)
+ .min(LocalDateTime::compareTo)
+ .orElse(null);
+ epic.setStartTime(earliestStart);
+
+ LocalDateTime latestEnd = epicSubtasks.stream()
+ .map(Subtask::getEndTime)
+ .filter(Objects::nonNull)
+ .max(LocalDateTime::compareTo)
+ .orElse(null);
+ epic.setEndTime(latestEnd);
}
}
\ No newline at end of file
diff --git a/src/manager/ManagerSaveException.java b/src/manager/ManagerSaveException.java
new file mode 100644
index 0000000..4ff500a
--- /dev/null
+++ b/src/manager/ManagerSaveException.java
@@ -0,0 +1,11 @@
+package manager;
+
+public class ManagerSaveException extends RuntimeException {
+ public ManagerSaveException(String message) {
+ super(message);
+ }
+
+ public ManagerSaveException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
\ No newline at end of file
diff --git a/src/manager/Managers.java b/src/manager/Managers.java
index 64dfb6f..e5d3bce 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 FileBackedTaskManager 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 09e55fa..e10d5c3 100644
--- a/src/manager/TaskManager.java
+++ b/src/manager/TaskManager.java
@@ -4,31 +4,60 @@
import model.Epic;
import model.Subtask;
import java.util.List;
+import java.util.Optional;
public interface TaskManager {
List getAllTasks();
+
void deleteAllTasks();
+
Task getTaskById(int id);
+
+ Optional getTaskByIdOptional(int id);
+
Task createTask(Task task);
+
void updateTask(Task task);
+
void deleteTaskById(int id);
List getAllEpics();
+
void deleteAllEpics();
+
Epic getEpicById(int id);
+
+ Optional getEpicByIdOptional(int id);
+
Epic createEpic(Epic epic);
+
void updateEpic(Epic epic);
+
void deleteEpicById(int id);
List getAllSubtasks();
+
void deleteAllSubtasks();
+
Subtask getSubtaskById(int id);
+
+ Optional getSubtaskByIdOptional(int id);
+
Subtask createSubtask(Subtask subtask);
+
void updateSubtask(Subtask subtask);
+
void deleteSubtaskById(int id);
List getSubtasksByEpicId(int epicId);
- // Новый метод для получения истории
List getHistory();
+
+ List getPrioritizedTasks();
+
+ boolean isTaskOverlapping(Task task);
+
+ boolean isTasksOverlapping(Task task1, Task task2);
+
+ boolean hasAnyTimeOverlaps();
}
\ No newline at end of file
diff --git a/src/manager/TaskType.java b/src/manager/TaskType.java
new file mode 100644
index 0000000..b95e27a
--- /dev/null
+++ b/src/manager/TaskType.java
@@ -0,0 +1,7 @@
+package model;
+
+public enum TaskType {
+ TASK,
+ EPIC,
+ SUBTASK
+}
\ No newline at end of file
diff --git a/src/model/Epic.java b/src/model/Epic.java
index 6634160..726cb44 100644
--- a/src/model/Epic.java
+++ b/src/model/Epic.java
@@ -1,31 +1,67 @@
package model;
+import java.time.Duration;
+import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
public class Epic extends Task {
private List subtaskIds;
+ private LocalDateTime endTime;
public Epic(String name, String description) {
super(name, description, Status.NEW);
this.subtaskIds = new ArrayList<>();
+ this.duration = Duration.ZERO;
}
- public List getSubtaskIds() { return new ArrayList<>(subtaskIds); }
- public void addSubtaskId(int subtaskId) { if (!subtaskIds.contains(subtaskId)) subtaskIds.add(subtaskId); }
- public void removeSubtaskId(int subtaskId) { subtaskIds.remove(Integer.valueOf(subtaskId)); }
- public void clearSubtasks() { subtaskIds.clear(); }
+ public Epic(String name, String description, int id, Status status, Duration duration,
+ LocalDateTime startTime, LocalDateTime endTime) {
+ super(name, description, id, status, duration, startTime);
+ this.subtaskIds = new ArrayList<>();
+ this.endTime = endTime;
+ }
+
+ public List getSubtaskIds() {
+ return new ArrayList<>(subtaskIds);
+ }
+
+ public void addSubtaskId(int subtaskId) {
+ if (!subtaskIds.contains(subtaskId)) {
+ subtaskIds.add(subtaskId);
+ }
+ }
+
+ public void removeSubtaskId(int subtaskId) {
+ subtaskIds.remove(Integer.valueOf(subtaskId));
+ }
+
+ public void clearSubtasks() {
+ subtaskIds.clear();
+ }
@Override
public void setStatus(Status status) {
throw new UnsupportedOperationException("Статус эпика рассчитывается автоматически");
}
- public void updateStatus(Status status) { this.status = status; }
+ public void updateStatus(Status status) {
+ this.status = status;
+ }
+
+ @Override
+ public LocalDateTime getEndTime() {
+ return endTime;
+ }
+
+ public void setEndTime(LocalDateTime endTime) {
+ this.endTime = endTime;
+ }
@Override
public String toString() {
- return String.format("Epic{name='%s', description='%s', id=%d, status=%s, subtaskIds=%s}",
- name, description, id, status, subtaskIds);
+ return String.format("Epic{name='%s', description='%s', id=%d, status=%s, "
+ + "duration=%s, startTime=%s, endTime=%s, subtaskIds=%s}",
+ name, description, id, status, duration, startTime, endTime, subtaskIds);
}
}
\ No newline at end of file
diff --git a/src/model/Subtask.java b/src/model/Subtask.java
index d1547d7..dfe9b32 100644
--- a/src/model/Subtask.java
+++ b/src/model/Subtask.java
@@ -1,24 +1,47 @@
package model;
+import java.time.Duration;
+import java.time.LocalDateTime;
+
public class Subtask extends Task {
private int epicId;
public Subtask(String name, String description, Status status, int epicId) {
super(name, description, status);
this.epicId = epicId;
+ this.duration = Duration.ZERO;
}
public Subtask(String name, String description, int id, Status status, int epicId) {
super(name, description, id, status);
this.epicId = epicId;
+ this.duration = Duration.ZERO;
+ }
+
+ public Subtask(String name, String description, Status status, int epicId,
+ Duration duration, LocalDateTime startTime) {
+ super(name, description, status, duration, startTime);
+ this.epicId = epicId;
}
- public int getEpicId() { return epicId; }
- public void setEpicId(int epicId) { this.epicId = epicId; }
+ public Subtask(String name, String description, int id, Status status, int epicId,
+ Duration duration, LocalDateTime startTime) {
+ super(name, description, id, status, duration, startTime);
+ this.epicId = epicId;
+ }
+
+ public int getEpicId() {
+ return epicId;
+ }
+
+ public void setEpicId(int epicId) {
+ this.epicId = epicId;
+ }
@Override
public String toString() {
- return String.format("Subtask{name='%s', description='%s', id=%d, status=%s, epicId=%d}",
- name, description, id, status, epicId);
+ return String.format("Subtask{name='%s', description='%s', id=%d, status=%s, "
+ + "duration=%s, startTime=%s, epicId=%d}",
+ name, description, id, status, duration, startTime, epicId);
}
}
\ No newline at end of file
diff --git a/src/model/Task.java b/src/model/Task.java
index 1547b36..35689d8 100644
--- a/src/model/Task.java
+++ b/src/model/Task.java
@@ -1,5 +1,7 @@
package model;
+import java.time.Duration;
+import java.time.LocalDateTime;
import java.util.Objects;
public class Task {
@@ -7,11 +9,14 @@ public class Task {
protected String description;
protected int id;
protected Status status;
+ protected Duration duration;
+ protected LocalDateTime startTime;
public Task(String name, String description, Status status) {
this.name = name;
this.description = description;
this.status = status;
+ this.duration = Duration.ZERO;
}
public Task(String name, String description, int id, Status status) {
@@ -19,31 +24,101 @@ public Task(String name, String description, int id, Status status) {
this.description = description;
this.id = id;
this.status = status;
+ this.duration = Duration.ZERO;
}
- public String getName() { return name; }
- public void setName(String name) { this.name = name; }
- public String getDescription() { return description; }
- public void setDescription(String description) { this.description = description; }
- public int getId() { return id; }
- public void setId(int id) { this.id = id; }
- public Status getStatus() { return status; }
- public void setStatus(Status status) { this.status = status; }
+ public Task(String name, String description, Status status, Duration duration, LocalDateTime startTime) {
+ this.name = name;
+ this.description = description;
+ this.status = status;
+ this.duration = duration;
+ this.startTime = startTime;
+ }
+
+ public Task(String name, String description, int id, Status status, Duration duration, LocalDateTime startTime) {
+ this.name = name;
+ this.description = description;
+ this.id = id;
+ this.status = status;
+ this.duration = duration;
+ this.startTime = startTime;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ 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 null;
+ }
+ return startTime.plus(duration);
+ }
@Override
public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
Task task = (Task) o;
return id == task.id;
}
@Override
- public int hashCode() { return Objects.hash(id); }
+ public int hashCode() {
+ return Objects.hash(id);
+ }
@Override
public String toString() {
- return String.format("Task{name='%s', description='%s', id=%d, status=%s}",
- name, description, id, status);
+ return String.format("Task{name='%s', description='%s', id=%d, status=%s, duration=%s, startTime=%s}",
+ name, description, id, status, duration, startTime);
}
}
\ No newline at end of file
diff --git a/test/TaskManagerTest.java b/test/TaskManagerTest.java
new file mode 100644
index 0000000..a5f7ca8
--- /dev/null
+++ b/test/TaskManagerTest.java
@@ -0,0 +1,313 @@
+
+import manager.TaskManager;
+import model.Epic;
+import model.Status;
+import model.Subtask;
+import model.Task;
+import org.junit.jupiter.api.Test;
+
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public abstract class TaskManagerTest {
+ protected T taskManager;
+
+ @Test
+ void testIsTasksOverlapping() {
+ LocalDateTime baseTime = LocalDateTime.now();
+
+ Task task1 = new Task("Task 1", "Description", Status.NEW,
+ Duration.ofMinutes(60), baseTime);
+ Task task2 = new Task("Task 2", "Description", Status.NEW,
+ Duration.ofMinutes(30), baseTime.plusMinutes(30));
+
+ assertTrue(taskManager.isTasksOverlapping(task1, task2));
+ }
+
+ @Test
+ void testIsTasksNotOverlapping() {
+ LocalDateTime baseTime = LocalDateTime.now();
+
+ Task task1 = new Task("Task 1", "Description", Status.NEW,
+ Duration.ofMinutes(30), baseTime);
+ Task task2 = new Task("Task 2", "Description", Status.NEW,
+ Duration.ofMinutes(30), baseTime.plusHours(1));
+
+ assertFalse(taskManager.isTasksOverlapping(task1, task2));
+ }
+
+ @Test
+ void testIsTasksTouchingNotOverlapping() {
+ LocalDateTime baseTime = LocalDateTime.now();
+
+ Task task1 = new Task("Task 1", "Description", Status.NEW,
+ Duration.ofMinutes(30), baseTime);
+ Task task2 = new Task("Task 2", "Description", Status.NEW,
+ Duration.ofMinutes(30), baseTime.plusMinutes(30));
+
+ assertFalse(taskManager.isTasksOverlapping(task1, task2));
+ }
+
+ @Test
+ void testHasAnyTimeOverlaps() {
+ LocalDateTime baseTime = LocalDateTime.now();
+
+ taskManager.createTask(new Task("Task 1", "Description", Status.NEW,
+ Duration.ofMinutes(60), baseTime));
+ taskManager.createTask(new Task("Task 2", "Description", Status.NEW,
+ Duration.ofMinutes(30), baseTime.plusMinutes(30)));
+
+ assertTrue(taskManager.hasAnyTimeOverlaps());
+ }
+
+ @Test
+ void testHasNoTimeOverlaps() {
+ LocalDateTime baseTime = LocalDateTime.now();
+
+ taskManager.createTask(new Task("Task 1", "Description", Status.NEW,
+ Duration.ofMinutes(30), baseTime));
+ taskManager.createTask(new Task("Task 2", "Description", Status.NEW,
+ Duration.ofMinutes(30), baseTime.plusHours(1)));
+
+ assertFalse(taskManager.hasAnyTimeOverlaps());
+ }
+
+ @Test
+ void testGetTaskByIdOptional() {
+ Task task = taskManager.createTask(new Task("Test", "Description", Status.NEW));
+
+ Optional result = taskManager.getTaskByIdOptional(task.getId());
+ assertTrue(result.isPresent());
+ assertEquals(task.getId(), result.get().getId());
+ }
+
+ @Test
+ void testGetTaskByIdOptionalNotFound() {
+ Optional result = taskManager.getTaskByIdOptional(999);
+ assertFalse(result.isPresent());
+ }
+
+ @Test
+ void testGetEpicByIdOptional() {
+ Epic epic = taskManager.createEpic(new Epic("Test", "Description"));
+
+ Optional result = taskManager.getEpicByIdOptional(epic.getId());
+ assertTrue(result.isPresent());
+ assertEquals(epic.getId(), result.get().getId());
+ }
+
+ @Test
+ void testGetSubtaskByIdOptional() {
+ Epic epic = taskManager.createEpic(new Epic("Epic", "Description"));
+ Subtask subtask = taskManager.createSubtask(new Subtask("Test", "Description", Status.NEW, epic.getId()));
+
+ Optional result = taskManager.getSubtaskByIdOptional(subtask.getId());
+ assertTrue(result.isPresent());
+ assertEquals(subtask.getId(), result.get().getId());
+ }
+
+ @Test
+ void getPrioritizedTasks_shouldReturnSortedTasks() {
+ LocalDateTime now = LocalDateTime.now();
+
+ Task task1 = taskManager.createTask(new Task("Task 1", "Description", Status.NEW,
+ Duration.ofMinutes(30), now.plusHours(2)));
+ Task task2 = taskManager.createTask(new Task("Task 2", "Description", Status.NEW,
+ Duration.ofMinutes(45), now.plusHours(1)));
+ Task task3 = taskManager.createTask(new Task("Task 3", "Description", Status.NEW,
+ Duration.ofMinutes(15), null));
+
+ List prioritized = taskManager.getPrioritizedTasks();
+
+ assertEquals(2, prioritized.size());
+ assertEquals(task2.getId(), prioritized.get(0).getId());
+ assertEquals(task1.getId(), prioritized.get(1).getId());
+ }
+
+ @Test
+ void testTaskOverlapping() {
+ LocalDateTime baseTime = LocalDateTime.now();
+
+ Task task1 = taskManager.createTask(new Task("Task 1", "Description", Status.NEW,
+ Duration.ofMinutes(60), baseTime));
+
+ Task overlappingTask = new Task("Overlapping", "Description", Status.NEW,
+ Duration.ofMinutes(30), baseTime.plusMinutes(30));
+
+ assertTrue(taskManager.isTaskOverlapping(overlappingTask));
+
+ Task nonOverlappingTask = new Task("Non-overlapping", "Description", Status.NEW,
+ Duration.ofMinutes(30), baseTime.plusHours(2));
+
+ assertFalse(taskManager.isTaskOverlapping(nonOverlappingTask));
+ }
+
+ @Test
+ void testEpicTimingCalculation() {
+ Epic epic = taskManager.createEpic(new Epic("Epic", "Description"));
+
+ LocalDateTime start1 = LocalDateTime.now();
+ LocalDateTime start2 = start1.plusHours(1);
+
+ Subtask subtask1 = taskManager.createSubtask(new Subtask("Sub 1", "Description", Status.NEW, epic.getId(),
+ Duration.ofMinutes(30), start1));
+ Subtask subtask2 = taskManager.createSubtask(new Subtask("Sub 2", "Description", Status.NEW, epic.getId(),
+ Duration.ofMinutes(45), start2));
+
+ Epic retrievedEpic = taskManager.getEpicById(epic.getId());
+
+ assertEquals(Duration.ofMinutes(75), retrievedEpic.getDuration());
+ assertEquals(start1, retrievedEpic.getStartTime());
+ assertEquals(start2.plusMinutes(45), retrievedEpic.getEndTime());
+ }
+
+ @Test
+ void testTaskWithNullTimeNotInPrioritized() {
+ Task task = taskManager.createTask(new Task("Task", "Description", Status.NEW,
+ Duration.ofMinutes(30), null));
+
+ List prioritized = taskManager.getPrioritizedTasks();
+
+ assertTrue(prioritized.isEmpty());
+ }
+
+ @Test
+ void testGetEndTime() {
+ LocalDateTime startTime = LocalDateTime.now();
+ Duration duration = Duration.ofMinutes(90);
+ Task task = new Task("Task", "Description", Status.NEW, duration, startTime);
+
+ LocalDateTime endTime = task.getEndTime();
+
+ assertEquals(startTime.plusMinutes(90), endTime);
+ }
+
+ @Test
+ void testGetEndTimeWithNullStartTime() {
+ Task task = new Task("Task", "Description", Status.NEW, Duration.ofMinutes(30), null);
+
+ assertNull(task.getEndTime());
+ }
+
+ @Test
+ void testEpicStatusAllNew() {
+ Epic epic = taskManager.createEpic(new Epic("Epic", "Description"));
+
+ taskManager.createSubtask(new Subtask("Sub 1", "Description", Status.NEW, epic.getId()));
+ taskManager.createSubtask(new Subtask("Sub 2", "Description", Status.NEW, epic.getId()));
+
+ assertEquals(Status.NEW, taskManager.getEpicById(epic.getId()).getStatus());
+ }
+
+ @Test
+ void testEpicStatusAllDone() {
+ Epic epic = taskManager.createEpic(new Epic("Epic", "Description"));
+
+ Subtask sub1 = taskManager.createSubtask(new Subtask("Sub 1", "Description", Status.NEW, epic.getId()));
+ Subtask sub2 = taskManager.createSubtask(new Subtask("Sub 2", "Description", Status.NEW, epic.getId()));
+
+ taskManager.updateSubtask(new Subtask("Sub 1", "Description", sub1.getId(), Status.DONE, epic.getId()));
+ taskManager.updateSubtask(new Subtask("Sub 2", "Description", sub2.getId(), Status.DONE, epic.getId()));
+
+ assertEquals(Status.DONE, taskManager.getEpicById(epic.getId()).getStatus());
+ }
+
+ @Test
+ void testEpicStatusMixedNewAndDone() {
+ Epic epic = taskManager.createEpic(new Epic("Epic", "Description"));
+
+ Subtask sub1 = taskManager.createSubtask(new Subtask("Sub 1", "Description", Status.NEW, epic.getId()));
+ Subtask sub2 = taskManager.createSubtask(new Subtask("Sub 2", "Description", Status.NEW, epic.getId()));
+
+ taskManager.updateSubtask(new Subtask("Sub 1", "Description", sub1.getId(), Status.DONE, epic.getId()));
+
+ assertEquals(Status.IN_PROGRESS, taskManager.getEpicById(epic.getId()).getStatus());
+ }
+
+ @Test
+ void testEpicStatusAllInProgress() {
+ Epic epic = taskManager.createEpic(new Epic("Epic", "Description"));
+
+ Subtask sub1 = taskManager.createSubtask(new Subtask("Sub 1", "Description", Status.NEW, epic.getId()));
+ Subtask sub2 = taskManager.createSubtask(new Subtask("Sub 2", "Description", Status.NEW, epic.getId()));
+
+ taskManager.updateSubtask(new Subtask("Sub 1", "Description", sub1.getId(), Status.IN_PROGRESS, epic.getId()));
+ taskManager.updateSubtask(new Subtask("Sub 2", "Description", sub2.getId(), Status.IN_PROGRESS, epic.getId()));
+
+ assertEquals(Status.IN_PROGRESS, taskManager.getEpicById(epic.getId()).getStatus());
+ }
+
+ @Test
+ void testHistoryManagerEmptyHistory() {
+ assertTrue(taskManager.getHistory().isEmpty());
+ }
+
+ @Test
+ void testHistoryManagerDuplicates() {
+ Task task = taskManager.createTask(new Task("Task", "Description", Status.NEW));
+
+ taskManager.getTaskById(task.getId());
+ taskManager.getTaskById(task.getId());
+ taskManager.getTaskById(task.getId());
+
+ assertEquals(1, taskManager.getHistory().size());
+ }
+
+ @Test
+ void testHistoryManagerRemoveFromBeginning() {
+ Task task1 = taskManager.createTask(new Task("Task 1", "Description", Status.NEW));
+ Task task2 = taskManager.createTask(new Task("Task 2", "Description", Status.NEW));
+ Task task3 = taskManager.createTask(new Task("Task 3", "Description", Status.NEW));
+
+ taskManager.getTaskById(task1.getId());
+ taskManager.getTaskById(task2.getId());
+ taskManager.getTaskById(task3.getId());
+
+ taskManager.deleteTaskById(task1.getId());
+
+ List history = taskManager.getHistory();
+ assertEquals(2, history.size());
+ assertEquals(task2.getId(), history.get(0).getId());
+ assertEquals(task3.getId(), history.get(1).getId());
+ }
+
+ @Test
+ void testHistoryManagerRemoveFromMiddle() {
+ Task task1 = taskManager.createTask(new Task("Task 1", "Description", Status.NEW));
+ Task task2 = taskManager.createTask(new Task("Task 2", "Description", Status.NEW));
+ Task task3 = taskManager.createTask(new Task("Task 3", "Description", Status.NEW));
+
+ taskManager.getTaskById(task1.getId());
+ taskManager.getTaskById(task2.getId());
+ taskManager.getTaskById(task3.getId());
+
+ taskManager.deleteTaskById(task2.getId());
+
+ List history = taskManager.getHistory();
+ assertEquals(2, history.size());
+ assertEquals(task1.getId(), history.get(0).getId());
+ assertEquals(task3.getId(), history.get(1).getId());
+ }
+
+ @Test
+ void testHistoryManagerRemoveFromEnd() {
+ Task task1 = taskManager.createTask(new Task("Task 1", "Description", Status.NEW));
+ Task task2 = taskManager.createTask(new Task("Task 2", "Description", Status.NEW));
+ Task task3 = taskManager.createTask(new Task("Task 3", "Description", Status.NEW));
+
+ taskManager.getTaskById(task1.getId());
+ taskManager.getTaskById(task2.getId());
+ taskManager.getTaskById(task3.getId());
+
+ taskManager.deleteTaskById(task3.getId());
+
+ List history = taskManager.getHistory();
+ assertEquals(2, history.size());
+ assertEquals(task1.getId(), history.get(0).getId());
+ assertEquals(task2.getId(), history.get(1).getId());
+ }
+}
\ No newline at end of file
diff --git a/test/http/HttpTaskServerTest.java b/test/http/HttpTaskServerTest.java
new file mode 100644
index 0000000..122ad57
--- /dev/null
+++ b/test/http/HttpTaskServerTest.java
@@ -0,0 +1,153 @@
+package http;
+
+import http.HttpTaskServer;
+import manager.Managers;
+import manager.TaskManager;
+import model.Task;
+import model.Status;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.time.Duration;
+import java.time.LocalDateTime;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class HttpTaskServerTest {
+ private TaskManager manager;
+ private HttpTaskServer server;
+ private HttpClient client;
+
+ @BeforeEach
+ void setUp() {
+ manager = Managers.getDefault();
+ server = new HttpTaskServer(manager);
+ server.start();
+ client = HttpClient.newHttpClient();
+ }
+
+ @AfterEach
+ void tearDown() {
+ server.stop();
+ }
+
+ @Test
+ void testCreateTask() throws Exception {
+ String taskJson = "{\"name\":\"Test Task\",\"description\":\"Test Description\"," +
+ "\"status\":\"NEW\",\"duration\":30,\"startTime\":\"2023-01-01T10:00:00\"}";
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create("http://localhost:8080/tasks"))
+ .POST(HttpRequest.BodyPublishers.ofString(taskJson))
+ .build();
+
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
+
+ assertEquals(201, response.statusCode());
+ assertEquals(1, manager.getAllTasks().size());
+ assertEquals("Test Task", manager.getAllTasks().get(0).getName());
+ }
+
+ @Test
+ void testGetTask() throws Exception {
+ Task task = manager.createTask(new Task("Test", "Desc", Status.NEW));
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create("http://localhost:8080/tasks/" + task.getId()))
+ .GET()
+ .build();
+
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
+
+ assertEquals(200, response.statusCode());
+ assertTrue(response.body().contains("Test"));
+ }
+
+ @Test
+ void testGetAllTasks() throws Exception {
+ manager.createTask(new Task("Task 1", "Desc 1", Status.NEW));
+ manager.createTask(new Task("Task 2", "Desc 2", Status.IN_PROGRESS));
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create("http://localhost:8080/tasks"))
+ .GET()
+ .build();
+
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
+
+ assertEquals(200, response.statusCode());
+ assertTrue(response.body().contains("Task 1"));
+ assertTrue(response.body().contains("Task 2"));
+ }
+
+ @Test
+ void testDeleteTask() throws Exception {
+ Task task = manager.createTask(new Task("Test", "Desc", Status.NEW));
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create("http://localhost:8080/tasks/" + task.getId()))
+ .DELETE()
+ .build();
+
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
+
+ assertEquals(201, response.statusCode());
+ assertEquals(0, manager.getAllTasks().size());
+ }
+
+ @Test
+ void testGetHistory() throws Exception {
+ Task task = manager.createTask(new Task("Test", "Desc", Status.NEW));
+ manager.getTaskById(task.getId());
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create("http://localhost:8080/history"))
+ .GET()
+ .build();
+
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
+
+ assertEquals(200, response.statusCode());
+ assertTrue(response.body().contains("Test"));
+ }
+
+ @Test
+ void testGetPrioritized() throws Exception {
+ Task task1 = manager.createTask(new Task("Task 1", "Desc 1", Status.NEW,
+ Duration.ofMinutes(30), LocalDateTime.now()));
+ Task task2 = manager.createTask(new Task("Task 2", "Desc 2", Status.NEW,
+ Duration.ofMinutes(45), LocalDateTime.now().plusHours(1)));
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create("http://localhost:8080/prioritized"))
+ .GET()
+ .build();
+
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
+
+ assertEquals(200, response.statusCode());
+ assertTrue(response.body().contains("Task 1"));
+ assertTrue(response.body().contains("Task 2"));
+
+ // Используем переменные, чтобы убрать предупреждения
+ assertNotNull(task1);
+ assertNotNull(task2);
+ }
+
+ @Test
+ void testTaskNotFound() throws Exception {
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create("http://localhost:8080/tasks/999"))
+ .GET()
+ .build();
+
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
+
+ assertEquals(404, response.statusCode());
+ }
+}
\ No newline at end of file
diff --git a/test/manager/ExceptionHandlingTest.java b/test/manager/ExceptionHandlingTest.java
new file mode 100644
index 0000000..445d384
--- /dev/null
+++ b/test/manager/ExceptionHandlingTest.java
@@ -0,0 +1,35 @@
+package manager;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import java.io.File;
+import java.nio.file.Path;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class ExceptionHandlingTest {
+
+ @TempDir
+ Path tempDir;
+
+ @Test
+ void managerSaveException_shouldBeThrownOnSaveError() {
+ File invalidFile = new File("/invalid/path/tasks.csv");
+ FileBackedTaskManager manager = new FileBackedTaskManager(invalidFile);
+
+ assertThrows(ManagerSaveException.class, () -> {
+ manager.save();
+ });
+ }
+
+ @Test
+ void noException_withValidFile() {
+ File validFile = tempDir.resolve("valid.csv").toFile();
+ FileBackedTaskManager manager = new FileBackedTaskManager(validFile);
+
+ assertDoesNotThrow(() -> {
+ manager.save();
+ });
+ }
+}
\ No newline at end of file
diff --git a/test/manager/FileBackedTest.java b/test/manager/FileBackedTest.java
new file mode 100644
index 0000000..a9a682f
--- /dev/null
+++ b/test/manager/FileBackedTest.java
@@ -0,0 +1,159 @@
+package manager;
+
+import manager.FileBackedTaskManager;
+import manager.ManagerSaveException;
+import model.*;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class FileBackedTaskManagerTest {
+
+ @TempDir
+ Path tempDir;
+
+ @Test
+ void testSaveAndLoadEmptyFile() {
+ File file = tempDir.resolve("test.csv").toFile();
+ FileBackedTaskManager manager = new FileBackedTaskManager(file);
+
+ // Сохраняем пустой менеджер
+ manager.save();
+
+ // Загружаем из файла
+ FileBackedTaskManager loadedManager = FileBackedTaskManager.loadFromFile(file);
+
+ assertTrue(loadedManager.getAllTasks().isEmpty());
+ assertTrue(loadedManager.getAllEpics().isEmpty());
+ assertTrue(loadedManager.getAllSubtasks().isEmpty());
+ }
+
+ @Test
+ void testSaveAndLoadMultipleTasks() {
+ File file = tempDir.resolve("test.csv").toFile();
+ FileBackedTaskManager manager = new FileBackedTaskManager(file);
+
+ // Создаем задачи
+ Task task1 = manager.createTask(new Task("Task 1", "Description 1", Status.NEW));
+ manager.createTask(new Task("Task 2", "Description 2", Status.DONE));
+
+ Epic epic = manager.createEpic(new Epic("Epic", "Epic description"));
+ manager.createSubtask(new Subtask("Subtask", "Sub description", Status.IN_PROGRESS, epic.getId()));
+
+ // Загружаем из файла
+ FileBackedTaskManager loadedManager = FileBackedTaskManager.loadFromFile(file);
+
+ assertEquals(2, loadedManager.getAllTasks().size());
+ assertEquals(1, loadedManager.getAllEpics().size());
+ assertEquals(1, loadedManager.getAllSubtasks().size());
+
+ Task loadedTask = loadedManager.getTaskById(task1.getId());
+ assertNotNull(loadedTask);
+ assertEquals("Task 1", loadedTask.getName());
+ assertEquals(Status.NEW, loadedTask.getStatus());
+ }
+
+ @Test
+ void testSaveException() {
+ File file = new File("/invalid/path/tasks.csv");
+ FileBackedTaskManager manager = new FileBackedTaskManager(file);
+
+ assertThrows(ManagerSaveException.class, () -> {
+ manager.createTask(new Task("Test", "Test", Status.NEW));
+ });
+ }
+
+ @Test
+ void testLoadFromNonExistentFile() {
+ File file = new File("nonexistent.csv");
+ FileBackedTaskManager manager = FileBackedTaskManager.loadFromFile(file);
+
+ assertNotNull(manager);
+ assertTrue(manager.getAllTasks().isEmpty());
+ }
+
+ // Новые тесты для спринта 8
+ @Test
+ void testSaveAndLoadWithTimeFields() {
+ File file = tempDir.resolve("test_time.csv").toFile();
+ FileBackedTaskManager manager = new FileBackedTaskManager(file);
+
+ LocalDateTime startTime = LocalDateTime.now();
+ Duration duration = Duration.ofMinutes(45);
+
+ // Создаем задачи с временными полями
+ Task task = manager.createTask(new Task("Task", "Description", Status.NEW, duration, startTime));
+ Epic epic = manager.createEpic(new Epic("Epic", "Description"));
+ Subtask subtask = manager.createSubtask(new Subtask("Subtask", "Description", Status.NEW,
+ epic.getId(), Duration.ofMinutes(30), startTime.plusHours(1)));
+
+ // Загружаем из файла
+ FileBackedTaskManager loadedManager = FileBackedTaskManager.loadFromFile(file);
+
+ Task loadedTask = loadedManager.getTaskById(task.getId());
+ assertNotNull(loadedTask);
+ assertEquals(duration, loadedTask.getDuration());
+ assertEquals(startTime, loadedTask.getStartTime());
+
+ Subtask loadedSubtask = loadedManager.getSubtaskById(subtask.getId());
+ assertNotNull(loadedSubtask);
+ assertEquals(Duration.ofMinutes(30), loadedSubtask.getDuration());
+ assertEquals(startTime.plusHours(1), loadedSubtask.getStartTime());
+
+ Epic loadedEpic = loadedManager.getEpicById(epic.getId());
+ assertNotNull(loadedEpic);
+ assertEquals(Duration.ofMinutes(30), loadedEpic.getDuration());
+ assertEquals(startTime.plusHours(1), loadedEpic.getStartTime());
+ }
+
+ @Test
+ void testPrioritizedTasksAfterLoad() {
+ File file = tempDir.resolve("test_prioritized.csv").toFile();
+ FileBackedTaskManager manager = new FileBackedTaskManager(file);
+
+ LocalDateTime now = LocalDateTime.now();
+
+ manager.createTask(new Task("Task 1", "Description", Status.NEW,
+ Duration.ofMinutes(30), now.plusHours(2)));
+ manager.createTask(new Task("Task 2", "Description", Status.NEW,
+ Duration.ofMinutes(45), now.plusHours(1)));
+
+ FileBackedTaskManager loadedManager = FileBackedTaskManager.loadFromFile(file);
+
+ List prioritized = loadedManager.getPrioritizedTasks();
+ assertEquals(2, prioritized.size());
+ assertEquals(now.plusHours(1), prioritized.get(0).getStartTime());
+ assertEquals(now.plusHours(2), prioritized.get(1).getStartTime());
+ }
+
+ @Test
+ void testSaveAndLoadEpicWithTimeCalculation() {
+ File file = tempDir.resolve("test_epic_time.csv").toFile();
+ FileBackedTaskManager manager = new FileBackedTaskManager(file);
+
+ Epic epic = manager.createEpic(new Epic("Epic", "Description"));
+
+ LocalDateTime start1 = LocalDateTime.of(2023, 1, 1, 10, 0);
+ LocalDateTime start2 = LocalDateTime.of(2023, 1, 1, 11, 0);
+
+ manager.createSubtask(new Subtask("Sub 1", "Description", Status.NEW, epic.getId(),
+ Duration.ofMinutes(30), start1));
+ manager.createSubtask(new Subtask("Sub 2", "Description", Status.NEW, epic.getId(),
+ Duration.ofMinutes(45), start2));
+
+ FileBackedTaskManager loadedManager = FileBackedTaskManager.loadFromFile(file);
+
+ Epic loadedEpic = loadedManager.getEpicById(epic.getId());
+ assertNotNull(loadedEpic);
+ assertEquals(Duration.ofMinutes(75), loadedEpic.getDuration());
+ assertEquals(start1, loadedEpic.getStartTime());
+ assertEquals(start2.plusMinutes(45), loadedEpic.getEndTime());
+ }
+}
\ No newline at end of file
diff --git a/test/manager/HistoryDataPreservationTest.java b/test/manager/HistoryDataPreservationTest.java
index b041735..32fab8d 100644
--- a/test/manager/HistoryDataPreservationTest.java
+++ b/test/manager/HistoryDataPreservationTest.java
@@ -15,39 +15,30 @@ void setUp() {
}
@Test
- void historyPreservesTaskData() {
- // Создаем задачу
+ void historyKeepsData() {
Task originalTask = new Task("Original", "Original Description", 1, Status.NEW);
- // Добавляем в историю
historyManager.add(originalTask);
- // Изменяем оригинальную задачу
originalTask.setName("Modified");
originalTask.setDescription("Modified Description");
originalTask.setStatus(Status.DONE);
- // Получаем задачу из истории
Task historicalTask = historyManager.getHistory().get(0);
- // Проверяем, что данные в истории сохранились оригинальными
- assertEquals("Original", historicalTask.getName(), "История должна сохранить оригинальное имя");
- assertEquals("Original Description", historicalTask.getDescription(),
- "История должна сохранить оригинальное описание");
- assertEquals(Status.NEW, historicalTask.getStatus(), "История должна сохранить оригинальный статус");
- assertEquals(1, historicalTask.getId(), "История должна сохранить оригинальный ID");
+ assertEquals("Original", historicalTask.getName());
+ assertEquals("Original Description", historicalTask.getDescription());
+ assertEquals(Status.NEW, historicalTask.getStatus());
+ assertEquals(1, historicalTask.getId());
}
@Test
- void historyContainsIndependentCopies() {
+ void historyHasCopies() {
Task task = new Task("Test", "Description", 1, Status.NEW);
historyManager.add(task);
- // Изменяем оригинальную задачу
task.setName("Changed");
- // Задача в истории не должна измениться
- assertNotEquals(task.getName(), historyManager.getHistory().get(0).getName(),
- "Задача в истории не должна зависеть от изменений оригинала");
+ assertNotEquals(task.getName(), historyManager.getHistory().get(0).getName());
}
}
\ No newline at end of file
diff --git a/test/manager/InMemoryTaskManagerTest.java b/test/manager/InMemoryTaskManagerTest.java
new file mode 100644
index 0000000..9d06c71
--- /dev/null
+++ b/test/manager/InMemoryTaskManagerTest.java
@@ -0,0 +1,461 @@
+package manager;
+
+import model.Task;
+import model.Epic;
+import model.Subtask;
+import model.Status;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.List;
+import java.time.Duration;
+import java.time.LocalDateTime;
+
+class InMemoryTaskManagerTest {
+ private TaskManager taskManager;
+
+ @BeforeEach
+ void setUp() {
+ taskManager = new InMemoryTaskManager();
+ }
+
+ @Test
+ void testCreateTask() {
+ Task task = new Task("Test Task", "Test Description", Status.NEW);
+ Task createdTask = taskManager.createTask(task);
+
+ assertNotNull(createdTask);
+ assertNotNull(createdTask.getId());
+ assertEquals("Test Task", createdTask.getName());
+ assertEquals("Test Description", createdTask.getDescription());
+ assertEquals(Status.NEW, createdTask.getStatus());
+
+ Task retrievedTask = taskManager.getTaskById(createdTask.getId());
+ assertEquals(createdTask, retrievedTask);
+ }
+
+ @Test
+ void testCreateEpic() {
+ Epic epic = new Epic("Test Epic", "Test Epic Description");
+ Epic createdEpic = taskManager.createEpic(epic);
+
+ assertNotNull(createdEpic);
+ assertNotNull(createdEpic.getId());
+ assertEquals("Test Epic", createdEpic.getName());
+ assertEquals("Test Epic Description", createdEpic.getDescription());
+ assertEquals(Status.NEW, createdEpic.getStatus());
+ assertTrue(createdEpic.getSubtaskIds().isEmpty());
+
+ Epic retrievedEpic = taskManager.getEpicById(createdEpic.getId());
+ assertEquals(createdEpic, retrievedEpic);
+ }
+
+ @Test
+ void testCreateSubtask() {
+ Epic epic = taskManager.createEpic(new Epic("Test Epic", "Description"));
+ Subtask subtask = new Subtask("Test Subtask", "Test Description", Status.NEW, epic.getId());
+ Subtask createdSubtask = taskManager.createSubtask(subtask);
+
+ assertNotNull(createdSubtask);
+ assertNotNull(createdSubtask.getId());
+ assertEquals("Test Subtask", createdSubtask.getName());
+ assertEquals("Test Description", createdSubtask.getDescription());
+ assertEquals(Status.NEW, createdSubtask.getStatus());
+ assertEquals(epic.getId(), createdSubtask.getEpicId());
+
+ Subtask retrievedSubtask = taskManager.getSubtaskById(createdSubtask.getId());
+ assertEquals(createdSubtask, retrievedSubtask);
+
+ List epicSubtasks = taskManager.getSubtasksByEpicId(epic.getId());
+ assertEquals(1, epicSubtasks.size());
+ assertEquals(createdSubtask.getId(), epicSubtasks.get(0).getId());
+ }
+
+ @Test
+ void testUpdateTask() {
+ Task task = taskManager.createTask(new Task("Original", "Desc", Status.NEW));
+ Task updatedTask = new Task("Updated", "Updated Desc", task.getId(), Status.IN_PROGRESS);
+
+ taskManager.updateTask(updatedTask);
+
+ Task retrievedTask = taskManager.getTaskById(task.getId());
+ assertEquals("Updated", retrievedTask.getName());
+ assertEquals("Updated Desc", retrievedTask.getDescription());
+ assertEquals(Status.IN_PROGRESS, retrievedTask.getStatus());
+ }
+
+ @Test
+ void testUpdateEpic() {
+ Epic epic = taskManager.createEpic(new Epic("Original", "Desc"));
+ Epic updatedEpic = new Epic("Updated", "Updated Desc");
+ updatedEpic.setId(epic.getId());
+
+ taskManager.updateEpic(updatedEpic);
+
+ Epic retrievedEpic = taskManager.getEpicById(epic.getId());
+ assertEquals("Updated", retrievedEpic.getName());
+ assertEquals("Updated Desc", retrievedEpic.getDescription());
+ }
+
+ @Test
+ void testUpdateSubtask() {
+ Epic epic = taskManager.createEpic(new Epic("Epic", "Desc"));
+ Subtask subtask = taskManager.createSubtask(new Subtask("Original", "Desc", Status.NEW, epic.getId()));
+ Subtask updatedSubtask = new Subtask("Updated", "Updated Desc", subtask.getId(), Status.DONE, epic.getId());
+
+ taskManager.updateSubtask(updatedSubtask);
+
+ Subtask retrievedSubtask = taskManager.getSubtaskById(subtask.getId());
+ assertEquals("Updated", retrievedSubtask.getName());
+ assertEquals("Updated Desc", retrievedSubtask.getDescription());
+ assertEquals(Status.DONE, retrievedSubtask.getStatus());
+ }
+
+ @Test
+ void testDeleteTask() {
+ Task task = taskManager.createTask(new Task("Test", "Desc", Status.NEW));
+ int taskId = task.getId();
+
+ taskManager.deleteTaskById(taskId);
+
+ assertNull(taskManager.getTaskById(taskId));
+ assertTrue(taskManager.getAllTasks().isEmpty());
+ }
+
+ @Test
+ void testDeleteEpic() {
+ Epic epic = taskManager.createEpic(new Epic("Test", "Desc"));
+ int epicId = epic.getId();
+
+ taskManager.deleteEpicById(epicId);
+
+ assertNull(taskManager.getEpicById(epicId));
+ assertTrue(taskManager.getAllEpics().isEmpty());
+ }
+
+ @Test
+ void testDeleteSubtask() {
+ Epic epic = taskManager.createEpic(new Epic("Epic", "Desc"));
+ Subtask subtask = taskManager.createSubtask(new Subtask("Test", "Desc", Status.NEW, epic.getId()));
+ int subtaskId = subtask.getId();
+
+ taskManager.deleteSubtaskById(subtaskId);
+
+ assertNull(taskManager.getSubtaskById(subtaskId));
+ assertTrue(taskManager.getAllSubtasks().isEmpty());
+ assertTrue(epic.getSubtaskIds().isEmpty());
+ }
+
+ @Test
+ void testDeleteAllTasks() {
+ taskManager.createTask(new Task("Task 1", "Desc", Status.NEW));
+ taskManager.createTask(new Task("Task 2", "Desc", Status.IN_PROGRESS));
+
+ taskManager.deleteAllTasks();
+
+ assertTrue(taskManager.getAllTasks().isEmpty());
+ }
+
+ @Test
+ void testDeleteAllEpics() {
+ taskManager.createEpic(new Epic("Epic 1", "Desc"));
+ taskManager.createEpic(new Epic("Epic 2", "Desc"));
+
+ taskManager.deleteAllEpics();
+
+ assertTrue(taskManager.getAllEpics().isEmpty());
+ assertTrue(taskManager.getAllSubtasks().isEmpty());
+ }
+
+ @Test
+ void testDeleteAllSubtasks() {
+ Epic epic = taskManager.createEpic(new Epic("Epic", "Desc"));
+ taskManager.createSubtask(new Subtask("Sub 1", "Desc", Status.NEW, epic.getId()));
+ taskManager.createSubtask(new Subtask("Sub 2", "Desc", Status.DONE, epic.getId()));
+
+ taskManager.deleteAllSubtasks();
+
+ assertTrue(taskManager.getAllSubtasks().isEmpty());
+ assertTrue(epic.getSubtaskIds().isEmpty());
+ }
+
+ @Test
+ void testGetAllTasks() {
+ Task task1 = taskManager.createTask(new Task("Task 1", "Desc", Status.NEW));
+ Task task2 = taskManager.createTask(new Task("Task 2", "Desc", Status.IN_PROGRESS));
+
+ List allTasks = taskManager.getAllTasks();
+
+ assertEquals(2, allTasks.size());
+ assertTrue(allTasks.contains(task1));
+ assertTrue(allTasks.contains(task2));
+ }
+
+ @Test
+ void testGetAllEpics() {
+ Epic epic1 = taskManager.createEpic(new Epic("Epic 1", "Desc"));
+ Epic epic2 = taskManager.createEpic(new Epic("Epic 2", "Desc"));
+
+ List allEpics = taskManager.getAllEpics();
+
+ assertEquals(2, allEpics.size());
+ assertTrue(allEpics.contains(epic1));
+ assertTrue(allEpics.contains(epic2));
+ }
+
+ @Test
+ void testGetAllSubtasks() {
+ Epic epic = taskManager.createEpic(new Epic("Epic", "Desc"));
+ Subtask subtask1 = taskManager.createSubtask(new Subtask("Sub 1", "Desc", Status.NEW, epic.getId()));
+ Subtask subtask2 = taskManager.createSubtask(new Subtask("Sub 2", "Desc", Status.DONE, epic.getId()));
+
+ List allSubtasks = taskManager.getAllSubtasks();
+
+ assertEquals(2, allSubtasks.size());
+ assertTrue(allSubtasks.contains(subtask1));
+ assertTrue(allSubtasks.contains(subtask2));
+ }
+
+ @Test
+ void testEpicStatus() {
+ Epic epic = taskManager.createEpic(new Epic("Epic", "Desc"));
+
+ assertEquals(Status.NEW, epic.getStatus());
+
+ Subtask sub1 = taskManager.createSubtask(new Subtask("Sub 1", "Desc", Status.NEW, epic.getId()));
+ Epic updatedEpic1 = taskManager.getEpicById(epic.getId());
+ assertEquals(Status.NEW, updatedEpic1.getStatus());
+
+ taskManager.updateSubtask(new Subtask("Sub 1", "Desc", sub1.getId(), Status.DONE, epic.getId()));
+ Epic updatedEpic2 = taskManager.getEpicById(epic.getId());
+ assertEquals(Status.DONE, updatedEpic2.getStatus());
+
+ Subtask sub2 = taskManager.createSubtask(new Subtask("Sub 2", "Desc", Status.NEW, epic.getId()));
+ Epic updatedEpic3 = taskManager.getEpicById(epic.getId());
+ assertEquals(Status.IN_PROGRESS, updatedEpic3.getStatus());
+
+ taskManager.updateSubtask(new Subtask("Sub 1", "Desc", sub1.getId(), Status.IN_PROGRESS, epic.getId()));
+ taskManager.updateSubtask(new Subtask("Sub 2", "Desc", sub2.getId(), Status.IN_PROGRESS, epic.getId()));
+ Epic updatedEpic4 = taskManager.getEpicById(epic.getId());
+ assertEquals(Status.IN_PROGRESS, updatedEpic4.getStatus());
+ }
+
+ @Test
+ void testHistoryNoDuplicates() {
+ Task task = taskManager.createTask(new Task("Test", "Description", Status.NEW));
+
+ taskManager.getTaskById(task.getId());
+ taskManager.getTaskById(task.getId());
+ taskManager.getTaskById(task.getId());
+
+ assertEquals(1, taskManager.getHistory().size());
+ }
+
+ @Test
+ void testTaskImmutability() {
+ Task task = taskManager.createTask(new Task("Test", "Description", Status.NEW));
+ int originalId = task.getId();
+
+ task.setId(999);
+ task.setName("Modified");
+
+ Task managedTask = taskManager.getTaskById(originalId);
+
+ assertEquals(originalId, managedTask.getId());
+ assertEquals("Test", managedTask.getName());
+ }
+
+ @Test
+ void testEpicImmutability() {
+ Epic epic = taskManager.createEpic(new Epic("Test Epic", "Description"));
+ int originalId = epic.getId();
+
+ epic.setId(999);
+ epic.setName("Modified");
+
+ Epic managedEpic = taskManager.getEpicById(originalId);
+
+ assertEquals(originalId, managedEpic.getId());
+ assertEquals("Test Epic", managedEpic.getName());
+ }
+
+ @Test
+ void testHistoryAfterDelete() {
+ Task task = taskManager.createTask(new Task("Test", "Description", Status.NEW));
+
+ taskManager.getTaskById(task.getId());
+ assertEquals(1, taskManager.getHistory().size());
+
+ taskManager.deleteTaskById(task.getId());
+
+ assertTrue(taskManager.getHistory().isEmpty());
+ }
+
+ @Test
+ void testDataIntegrity() {
+ Epic epic = taskManager.createEpic(new Epic("Test Epic", "Description"));
+ Subtask subtask = taskManager.createSubtask(new Subtask("Subtask", "Desc", Status.NEW, epic.getId()));
+
+ int subtaskId = subtask.getId();
+ int epicId = epic.getId();
+
+ taskManager.deleteSubtaskById(subtaskId);
+
+ Epic updatedEpic = taskManager.getEpicById(epicId);
+ assertFalse(updatedEpic.getSubtaskIds().contains(subtaskId));
+
+ assertNull(taskManager.getSubtaskById(subtaskId));
+ }
+
+ @Test
+ void testCreateNullTask() {
+ Task result = taskManager.createTask(null);
+ assertNull(result);
+ }
+
+ @Test
+ void testCreateNullEpic() {
+ Epic result = taskManager.createEpic(null);
+ assertNull(result);
+ }
+
+ @Test
+ void testCreateNullSubtask() {
+ Subtask result = taskManager.createSubtask(null);
+ assertNull(result);
+ }
+
+ @Test
+ void testCreateSubtaskBadEpic() {
+ Subtask subtask = new Subtask("Test", "Desc", Status.NEW, 999);
+ Subtask result = taskManager.createSubtask(subtask);
+ assertNull(result);
+ }
+
+ @Test
+ void testUpdateBadTask() {
+ Task task = new Task("Test", "Desc", 999, Status.NEW);
+ taskManager.updateTask(task);
+
+ assertNull(taskManager.getTaskById(999));
+ }
+
+ @Test
+ void testUpdateBadEpic() {
+ Epic epic = new Epic("Test", "Desc");
+ epic.setId(999);
+ taskManager.updateEpic(epic);
+
+ assertNull(taskManager.getEpicById(999));
+ }
+
+ @Test
+ void testUpdateBadSubtask() {
+ Epic epic = taskManager.createEpic(new Epic("Epic", "Desc"));
+ Subtask subtask = new Subtask("Test", "Desc", 999, Status.NEW, epic.getId());
+ taskManager.updateSubtask(subtask);
+
+ assertNull(taskManager.getSubtaskById(999));
+ }
+
+ @Test
+ void testDeleteBadTask() {
+ taskManager.deleteTaskById(999);
+ }
+
+ @Test
+ void testDeleteBadEpic() {
+ taskManager.deleteEpicById(999);
+ }
+
+ @Test
+ void testDeleteBadSubtask() {
+ taskManager.deleteSubtaskById(999);
+ }
+
+ @Test
+ void testGetBadTask() {
+ Task task = taskManager.getTaskById(999);
+ assertNull(task);
+ }
+
+ @Test
+ void testGetBadEpic() {
+ Epic epic = taskManager.getEpicById(999);
+ assertNull(epic);
+ }
+
+ @Test
+ void testGetBadSubtask() {
+ Subtask subtask = taskManager.getSubtaskById(999);
+ assertNull(subtask);
+ }
+
+ @Test
+ void testGetSubtasksBadEpic() {
+ List subtasks = taskManager.getSubtasksByEpicId(999);
+ assertTrue(subtasks.isEmpty());
+ }
+
+ // Новые тесты для спринта 8
+ @Test
+ void testCreateTaskWithTime() {
+ LocalDateTime startTime = LocalDateTime.now();
+ Duration duration = Duration.ofMinutes(30);
+ Task task = new Task("Test Task", "Test Description", Status.NEW, duration, startTime);
+ Task createdTask = taskManager.createTask(task);
+
+ assertNotNull(createdTask);
+ assertEquals(duration, createdTask.getDuration());
+ assertEquals(startTime, createdTask.getStartTime());
+ assertEquals(startTime.plus(duration), createdTask.getEndTime());
+ }
+
+ @Test
+ void testGetPrioritizedTasks() {
+ LocalDateTime now = LocalDateTime.now();
+
+ Task task1 = taskManager.createTask(new Task("Task 1", "Description", Status.NEW,
+ Duration.ofMinutes(30), now.plusHours(2)));
+ Task task2 = taskManager.createTask(new Task("Task 2", "Description", Status.NEW,
+ Duration.ofMinutes(45), now.plusHours(1)));
+ Task task3 = taskManager.createTask(new Task("Task 3", "Description", Status.NEW,
+ Duration.ofMinutes(15), null));
+
+ List prioritized = taskManager.getPrioritizedTasks();
+
+ assertEquals(2, prioritized.size());
+ assertEquals(task2.getId(), prioritized.get(0).getId());
+ assertEquals(task1.getId(), prioritized.get(1).getId());
+ }
+
+ @Test
+ void testTaskOverlapping() {
+ LocalDateTime baseTime = LocalDateTime.now();
+
+ Task task1 = taskManager.createTask(new Task("Task 1", "Description", Status.NEW,
+ Duration.ofMinutes(60), baseTime));
+
+ Task overlappingTask = new Task("Overlapping", "Description", Status.NEW,
+ Duration.ofMinutes(30), baseTime.plusMinutes(30));
+
+ assertTrue(taskManager.isTaskOverlapping(overlappingTask));
+ }
+
+ @Test
+ void testCreateOverlappingTaskShouldFail() {
+ LocalDateTime baseTime = LocalDateTime.now();
+
+ taskManager.createTask(new Task("Task 1", "Description", Status.NEW,
+ Duration.ofMinutes(60), baseTime));
+
+ Task overlappingTask = new Task("Overlapping", "Description", Status.NEW,
+ Duration.ofMinutes(30), baseTime.plusMinutes(30));
+
+ Task result = taskManager.createTask(overlappingTask);
+
+ assertNull(result);
+ assertEquals(1, taskManager.getAllTasks().size());
+ }
+}
\ No newline at end of file
diff --git a/test/manager/TaskInheritanceTest.java b/test/manager/TaskInheritanceTest.java
deleted file mode 100644
index b723370..0000000
--- a/test/manager/TaskInheritanceTest.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package manager;
-
-import model.Epic;
-import model.Status;
-import model.Subtask;
-import model.Task;
-import org.junit.jupiter.api.Test;
-import static org.junit.jupiter.api.Assertions.*;
-
-class TaskInheritanceTest {
-
- @Test
- void taskAndSubtaskWithSameIdShouldNotBeEqual() {
- Task task = new Task("Task", "Description", 1, Status.NEW);
- Subtask subtask = new Subtask("Subtask", "Description", 1, Status.NEW, 2);
-
- assertNotEquals(task, subtask, "Task и Subtask с одинаковым ID не должны быть равны");
- }
-
- @Test
- void subtasksWithSameIdShouldBeEqual() {
- Subtask subtask1 = new Subtask("Subtask 1", "Description 1", 1, Status.NEW, 10);
- Subtask subtask2 = new Subtask("Subtask 2", "Description 2", 1, Status.DONE, 20);
-
- assertEquals(subtask1, subtask2, "Subtask с одинаковым ID должны быть равны");
- }
-
- @Test
- void epicsWithSameIdShouldBeEqual() {
- Epic epic1 = new Epic("Epic 1", "Description 1");
- epic1.setId(1);
- Epic epic2 = new Epic("Epic 2", "Description 2");
- epic2.setId(1);
-
- assertEquals(epic1, epic2, "Epic с одинаковым ID должны быть равны");
- }
-}
\ No newline at end of file
diff --git a/test/manager/TaskManagerFunctionalityTest.java b/test/manager/TaskManagerFunctionalityTest.java
index 36e024b..60e4e49 100644
--- a/test/manager/TaskManagerFunctionalityTest.java
+++ b/test/manager/TaskManagerFunctionalityTest.java
@@ -18,24 +18,20 @@ void setUp() {
@Test
void canAddAndFindAllTaskTypes() {
- // Создаем задачи всех типов
Task task = taskManager.createTask(new Task("Task", "Description", Status.NEW));
Epic epic = taskManager.createEpic(new Epic("Epic", "Description"));
Subtask subtask = taskManager.createSubtask(new Subtask("Subtask", "Description", Status.NEW, epic.getId()));
- // Проверяем, что все создались
- assertNotNull(task, "Задача должна быть создана");
- assertNotNull(epic, "Epic должен быть создан");
- assertNotNull(subtask, "Subtask должен быть создан");
+ assertNotNull(task);
+ assertNotNull(epic);
+ assertNotNull(subtask);
- // Проверяем поиск по ID
- assertNotNull(taskManager.getTaskById(task.getId()), "Должна найтись задача по ID");
- assertNotNull(taskManager.getEpicById(epic.getId()), "Должен найтись epic по ID");
- assertNotNull(taskManager.getSubtaskById(subtask.getId()), "Должен найтись subtask по ID");
+ assertNotNull(taskManager.getTaskById(task.getId()));
+ assertNotNull(taskManager.getEpicById(epic.getId()));
+ assertNotNull(taskManager.getSubtaskById(subtask.getId()));
- // Проверяем получение всех задач
- assertEquals(1, taskManager.getAllTasks().size(), "Должна быть 1 задача");
- assertEquals(1, taskManager.getAllEpics().size(), "Должен быть 1 epic");
- assertEquals(1, taskManager.getAllSubtasks().size(), "Должен быть 1 subtask");
+ assertEquals(1, taskManager.getAllTasks().size());
+ assertEquals(1, taskManager.getAllEpics().size());
+ assertEquals(1, taskManager.getAllSubtasks().size());
}
}
\ No newline at end of file
diff --git a/test/model/EpicIntegrationTest.java b/test/model/EpicIntegrationTest.java
index 772bb13..dfeb69f 100644
--- a/test/model/EpicIntegrationTest.java
+++ b/test/model/EpicIntegrationTest.java
@@ -18,10 +18,10 @@ void setUp() {
void epicCannotBeAddedAsItsOwnSubtask() {
Epic epic = taskManager.createEpic(new Epic("Test Epic", "Description"));
- // Пытаемся создать подзадачу с epicId равным ID самого эпика
- Subtask invalidSubtask = new Subtask("Invalid", "Description", Status.NEW, epic.getId());
+ // Пытаемся создать подзадачу с epicId равным ID самого эпика и id равным epicId
+ Subtask invalidSubtask = new Subtask("Invalid", "Description", epic.getId(), Status.NEW, epic.getId());
- // Должен вернуть null, так как epic не может быть своим же эпиком
+ // Должен вернуть null, так как epic не может быть своей же подзадачей
assertNull(taskManager.createSubtask(invalidSubtask),
"Epic не должен быть добавлен в качестве своей же подзадачи");
}
diff --git a/test/model/InMemoryHistoryManagerTest.java b/test/model/InMemoryHistoryManagerTest.java
new file mode 100644
index 0000000..430cfcb
--- /dev/null
+++ b/test/model/InMemoryHistoryManagerTest.java
@@ -0,0 +1,153 @@
+package manager;
+
+import model.Task;
+import model.Status;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.List;
+
+class InMemoryHistoryManagerTest {
+ private HistoryManager historyManager;
+
+ @BeforeEach
+ void setUp() {
+ historyManager = new InMemoryHistoryManager();
+ }
+
+ @Test
+ void testAddAndGetHistory() {
+ Task task = new Task("Test", "Description", Status.NEW);
+ task.setId(1);
+
+ historyManager.add(task);
+ List history = historyManager.getHistory();
+
+ assertEquals(1, history.size());
+ assertEquals(task, history.get(0));
+ }
+
+ @Test
+ void testRemoveDuplicates() {
+ Task task = new Task("Test", "Description", Status.NEW);
+ task.setId(1);
+
+ historyManager.add(task);
+ historyManager.add(task); // Дубликат
+ historyManager.add(task); // Еще один дубликат
+
+ List history = historyManager.getHistory();
+ assertEquals(1, history.size());
+ }
+
+ @Test
+ void testRemoveFromHistory() {
+ Task task1 = new Task("Test1", "Description1", Status.NEW);
+ Task task2 = new Task("Test2", "Description2", Status.NEW);
+ task1.setId(1);
+ 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));
+ }
+
+ @Test
+ void testHistoryOrderPreservation() {
+ Task task1 = new Task("Test1", "Description1", Status.NEW);
+ Task task2 = new Task("Test2", "Description2", Status.NEW);
+ Task task3 = new Task("Test3", "Description3", Status.NEW);
+ task1.setId(1);
+ task2.setId(2);
+ task3.setId(3);
+
+ historyManager.add(task1);
+ historyManager.add(task2);
+ historyManager.add(task3);
+
+ List history = historyManager.getHistory();
+
+ assertEquals(3, history.size());
+ assertEquals(task1, history.get(0));
+ assertEquals(task2, history.get(1));
+ assertEquals(task3, history.get(2));
+ }
+
+ @Test
+ void testRemoveNonExistentTask() {
+ // Удаление несуществующей задачи не должно вызывать исключений
+ assertDoesNotThrow(() -> historyManager.remove(999));
+ }
+
+ @Test
+ void testEmptyHistory() {
+ assertTrue(historyManager.getHistory().isEmpty());
+ }
+
+ // Новые тесты для спринта 8
+ @Test
+ void testRemoveFromBeginning() {
+ Task task1 = createTask(1, "Task 1");
+ Task task2 = createTask(2, "Task 2");
+ Task task3 = createTask(3, "Task 3");
+
+ historyManager.add(task1);
+ historyManager.add(task2);
+ historyManager.add(task3);
+
+ historyManager.remove(1);
+
+ List history = historyManager.getHistory();
+ assertEquals(2, history.size());
+ assertEquals(task2.getId(), history.get(0).getId());
+ assertEquals(task3.getId(), history.get(1).getId());
+ }
+
+ @Test
+ void testRemoveFromMiddle() {
+ Task task1 = createTask(1, "Task 1");
+ Task task2 = createTask(2, "Task 2");
+ Task task3 = createTask(3, "Task 3");
+
+ historyManager.add(task1);
+ historyManager.add(task2);
+ historyManager.add(task3);
+
+ historyManager.remove(2);
+
+ List history = historyManager.getHistory();
+ assertEquals(2, history.size());
+ assertEquals(task1.getId(), history.get(0).getId());
+ assertEquals(task3.getId(), history.get(1).getId());
+ }
+
+ @Test
+ void testRemoveFromEnd() {
+ Task task1 = createTask(1, "Task 1");
+ Task task2 = createTask(2, "Task 2");
+ Task task3 = createTask(3, "Task 3");
+
+ historyManager.add(task1);
+ historyManager.add(task2);
+ historyManager.add(task3);
+
+ historyManager.remove(3);
+
+ List history = historyManager.getHistory();
+ assertEquals(2, history.size());
+ assertEquals(task1.getId(), history.get(0).getId());
+ assertEquals(task2.getId(), history.get(1).getId());
+ }
+
+ private Task createTask(int id, String name) {
+ Task task = new Task(name, "Description", Status.NEW);
+ task.setId(id);
+ return task;
+ }
+}
\ No newline at end of file
diff --git a/test/model/SubtaskIntegrationTest.java b/test/model/SubtaskIntegrationTest.java
index 084c298..aff2157 100644
--- a/test/model/SubtaskIntegrationTest.java
+++ b/test/model/SubtaskIntegrationTest.java
@@ -19,12 +19,11 @@ void subtaskCannotBeItsOwnEpic() {
Epic epic = taskManager.createEpic(new Epic("Test Epic", "Description"));
Subtask subtask = taskManager.createSubtask(new Subtask("Subtask", "Description", Status.NEW, epic.getId()));
- // Пытаемся изменить epicId подзадачи на её собственный ID
- subtask.setEpicId(subtask.getId());
- taskManager.updateSubtask(subtask);
+ // Создаем подзадачу, которая пытается быть своим же эпиком
+ Subtask invalidSubtask = new Subtask("Invalid", "Description", subtask.getId(), Status.NEW, subtask.getId());
- // Epic ID не должен измениться на собственный ID подзадачи
- assertNotEquals(subtask.getId(), subtask.getEpicId(),
- "Subtask не должен быть своим же эпиком");
+ // Попытка создания должна вернуть null
+ Subtask result = taskManager.createSubtask(invalidSubtask);
+ assertNull(result, "Subtask не должен быть своим же эпиком");
}
}
\ No newline at end of file
diff --git a/test/model/TaskIdConflictTest.java b/test/model/TaskIdConflictTest.java
index 222e673..2859284 100644
--- a/test/model/TaskIdConflictTest.java
+++ b/test/model/TaskIdConflictTest.java
@@ -1,7 +1,7 @@
package model;
-import model.Task;
-import model.Status;
+import manager.InMemoryTaskManager;
+import manager.TaskManager;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
@@ -15,28 +15,23 @@ void setUp() {
}
@Test
- void noConflictBetweenGeneratedAndManualIds() {
- // Создаем задачу с автоматически сгенерированным ID
+ void testNoIdConflict() {
Task autoTask = taskManager.createTask(new Task("Auto", "Description", Status.NEW));
- // Создаем задачу вручную с таким же ID
Task manualTask = new Task("Manual", "Description", autoTask.getId(), Status.NEW);
- // Пытаемся обновить задачу с существующим ID
taskManager.updateTask(manualTask);
- // Проверяем, что задача обновилась, а не создалась новая
- assertEquals(1, taskManager.getAllTasks().size(), "Должна остаться одна задача");
- assertEquals("Manual", taskManager.getTaskById(autoTask.getId()).getName(),
- "Задача должна быть обновлена, а не создана новая");
+ assertEquals(1, taskManager.getAllTasks().size());
+ assertEquals("Manual", taskManager.getTaskById(autoTask.getId()).getName());
}
@Test
- void tasksWithDifferentIdsCoexist() {
+ void testDifferentIds() {
Task task1 = taskManager.createTask(new Task("Task 1", "Description", Status.NEW));
Task task2 = taskManager.createTask(new Task("Task 2", "Description", Status.NEW));
- assertNotEquals(task1.getId(), task2.getId(), "Задачи должны иметь разные ID");
- assertEquals(2, taskManager.getAllTasks().size(), "Обе задачи должны существовать");
+ assertNotEquals(task1.getId(), task2.getId());
+ assertEquals(2, taskManager.getAllTasks().size());
}
}
\ No newline at end of file
diff --git a/test/model/TaskImmutabilityTest.java b/test/model/TaskImmutabilityTest.java
deleted file mode 100644
index ff8b490..0000000
--- a/test/model/TaskImmutabilityTest.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package model;
-
-import model.Task;
-import model.Status;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import static org.junit.jupiter.api.Assertions.*;
-
-class TaskImmutabilityTest {
- private TaskManager taskManager;
-
- @BeforeEach
- void setUp() {
- taskManager = new InMemoryTaskManager();
- }
-
- @Test
- void taskRemainsUnchangedWhenAddedToManager() {
- // Создаем оригинальную задачу
- Task originalTask = new Task("Original", "Original Description", Status.NEW);
-
- // Сохраняем оригинальные значения
- String originalName = originalTask.getName();
- String originalDescription = originalTask.getDescription();
- Status originalStatus = originalTask.getStatus();
-
- // Добавляем в менеджер
- Task createdTask = taskManager.createTask(originalTask);
-
- // Проверяем, что оригинальная задача не изменилась
- assertEquals(originalName, originalTask.getName(), "Оригинальное имя не должно измениться");
- assertEquals(originalDescription, originalTask.getDescription(), "Оригинальное описание не должно измениться");
- assertEquals(originalStatus, originalTask.getStatus(), "Оригинальный статус не должен измениться");
-
- // Проверяем, что созданная задача имеет те же значения
- assertEquals(originalName, createdTask.getName(), "Имя должно сохраниться");
- assertEquals(originalDescription, createdTask.getDescription(), "Описание должно сохраниться");
- assertEquals(originalStatus, createdTask.getStatus(), "Статус должен сохраниться");
- }
-}
\ No newline at end of file
diff --git a/test/model/TaskTest.java b/test/model/TaskTest.java
deleted file mode 100644
index 67329c9..0000000
--- a/test/model/TaskTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package model;
-
-import model.Status;
-import model.Task;
-import org.junit.jupiter.api.Test;
-import static org.junit.jupiter.api.Assertions.*;
-
-class TaskTest {
-
- @Test
- void tasksWithSameIdShouldBeEqual() {
- Task task1 = new Task("Task 1", "Description 1", 1, Status.NEW);
- Task task2 = new Task("Task 2", "Description 2", 1, Status.DONE);
-
- assertEquals(task1, task2, "Задачи с одинаковым ID должны быть равны");
- assertEquals(task1.hashCode(), task2.hashCode(), "HashCode должен совпадать для одинаковых ID");
- }
-
- @Test
- void tasksWithDifferentIdShouldNotBeEqual() {
- Task task1 = new Task("Task", "Description", 1, Status.NEW);
- Task task2 = new Task("Task", "Description", 2, Status.NEW);
-
- assertNotEquals(task1, task2, "Задачи с разными ID не должны быть равны");
- }
-}
\ No newline at end of file