From 1e398fd87babd4afcbe9b56073e0a4b28217612c Mon Sep 17 00:00:00 2001 From: Belkin Ivan Date: Fri, 16 May 2025 00:40:36 +0300 Subject: [PATCH] =?UTF-8?q?=D0=92=D1=8B=D0=BF=D0=BE=D0=BB=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=BE=20=D1=84=D0=B8=D0=BD=D0=B0=D0=BB=D1=8C=D0=BD=D0=BE?= =?UTF-8?q?=D0=B5=20=D0=B7=D0=B0=D0=B4=D0=B0=D0=BD=D0=B8=D0=B5=209=20?= =?UTF-8?q?=D1=81=D0=BF=D1=80=D0=B8=D0=BD=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- java-kanban.iml | 9 + src/BaseHttpHandler.java | 96 +++++++++ src/DurationAdapter.java | 25 +++ src/Endpoint.java | 10 + src/ExceptionHandler.java | 27 +++ src/HttpEpicsController.java | 53 +++++ src/HttpHistoryController.java | 26 +++ src/HttpPrioritizedController.java | 26 +++ src/HttpSubtasksController.java | 52 +++++ src/HttpTaskServer.java | 52 +++++ src/HttpTasksController.java | 51 +++++ src/InMemoryTaskManager.java | 204 ++++++++++++------ src/LocalDateTimeAdapter.java | 28 +++ src/Managers.java | 2 +- src/NotFoundException.java | 5 + src/TaskManager.java | 1 + src/TaskOverlapsException.java | 5 + test/HttpTaskServerEpicsTest.java | 253 ++++++++++++++++++++++ test/HttpTaskServerHistoryTest.java | 99 +++++++++ test/HttpTaskServerPrioritizedTest.java | 83 ++++++++ test/HttpTaskServerSubtasksTest.java | 265 ++++++++++++++++++++++++ test/HttpTaskServerTasksTest.java | 244 ++++++++++++++++++++++ test/TaskManagerTest.java | 7 +- 23 files changed, 1562 insertions(+), 61 deletions(-) create mode 100644 src/BaseHttpHandler.java create mode 100644 src/DurationAdapter.java create mode 100644 src/Endpoint.java create mode 100644 src/ExceptionHandler.java create mode 100644 src/HttpEpicsController.java create mode 100644 src/HttpHistoryController.java create mode 100644 src/HttpPrioritizedController.java create mode 100644 src/HttpSubtasksController.java create mode 100644 src/HttpTaskServer.java create mode 100644 src/HttpTasksController.java create mode 100644 src/LocalDateTimeAdapter.java create mode 100644 src/NotFoundException.java create mode 100644 src/TaskOverlapsException.java create mode 100644 test/HttpTaskServerEpicsTest.java create mode 100644 test/HttpTaskServerHistoryTest.java create mode 100644 test/HttpTaskServerPrioritizedTest.java create mode 100644 test/HttpTaskServerSubtasksTest.java create mode 100644 test/HttpTaskServerTasksTest.java diff --git a/java-kanban.iml b/java-kanban.iml index 66c15d2..ee55ee2 100644 --- a/java-kanban.iml +++ b/java-kanban.iml @@ -24,5 +24,14 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/BaseHttpHandler.java b/src/BaseHttpHandler.java new file mode 100644 index 0000000..6f7e7ff --- /dev/null +++ b/src/BaseHttpHandler.java @@ -0,0 +1,96 @@ +import com.google.gson.Gson; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +public abstract class BaseHttpHandler implements HttpHandler { + protected final TaskManager taskManager; + protected final Gson gson; + + protected BaseHttpHandler(TaskManager taskManager, Gson gson) { + this.taskManager = taskManager; + this.gson = gson; + } + + public static void sendText(HttpExchange h, String text) throws IOException { + send(h, text, 200); + } + + public static void sendSuccessfullyModified(HttpExchange h, String text) throws IOException { + send(h, text, 201); + } + + public static void sendNotFound(HttpExchange h, String text) throws IOException { + send(h, text, 404); + } + + public static void sendHasInteractions(HttpExchange h, String text) throws IOException { + send(h, text, 406); + } + + public static void sendIntervalServerError(HttpExchange h, String text) throws IOException { + send(h, text, 500); + } + + public Endpoint getEndpoint(String[] pathParts, String requestMethod) { + if (pathParts[1].equals("tasks") || pathParts[1].equals("subtasks") || pathParts[1].equals("epics") || + pathParts[1].equals("history") || pathParts[1].equals("prioritized")) { + switch (requestMethod) { + case "GET": { + if (pathParts.length == 2) { + return Endpoint.GET; + } + if (pathParts.length == 3 && isInteger(pathParts[2])) { + return Endpoint.GET_ID; + } + if (pathParts.length == 4 && pathParts[1].equals("epics") && + isInteger(pathParts[2]) && pathParts[3].equals("subtasks")) { + return Endpoint.GET_ID_EPIC_SUBTASKS; + } + return Endpoint.UNKNOWN; + } + case "POST": { + if (pathParts.length == 2) { + return Endpoint.POST; + } + if (pathParts.length == 3 && isInteger(pathParts[2])) { + return Endpoint.POST_ID; + } + return Endpoint.UNKNOWN; + } + case "DELETE": { + if (pathParts.length == 2) { + return Endpoint.DELETE; + } + if (pathParts.length == 3 && isInteger(pathParts[2])) { + return Endpoint.DELETE_ID; + } + return Endpoint.UNKNOWN; + } + default: + return Endpoint.UNKNOWN; + } + } + return Endpoint.UNKNOWN; + } + + private static void send(HttpExchange h, String text, int code) throws IOException { + byte[] resp = text.getBytes(StandardCharsets.UTF_8); + h.getResponseHeaders().add("Content-Type", "application/json;charset=utf-8"); + h.sendResponseHeaders(code, resp.length); + h.getResponseBody().write(resp); + h.close(); + } + + private boolean isInteger(String s) { + try { + Integer.parseInt(s); + return true; + } catch (NumberFormatException e) { + return false; + } + } + +} \ No newline at end of file diff --git a/src/DurationAdapter.java b/src/DurationAdapter.java new file mode 100644 index 0000000..a268154 --- /dev/null +++ b/src/DurationAdapter.java @@ -0,0 +1,25 @@ +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import java.io.IOException; +import java.time.Duration; + +public class DurationAdapter extends TypeAdapter { + @Override + public void write(JsonWriter jsonWriter, Duration duration) throws IOException { + if (duration == null) { + jsonWriter.nullValue(); + } else { + jsonWriter.value(duration.toString()); + } + } + + @Override + public Duration read(JsonReader jsonReader) throws IOException { + if (jsonReader == null) { + return null; + } + return Duration.parse(jsonReader.nextString()); + } +} \ No newline at end of file diff --git a/src/Endpoint.java b/src/Endpoint.java new file mode 100644 index 0000000..dd37a9a --- /dev/null +++ b/src/Endpoint.java @@ -0,0 +1,10 @@ +public enum Endpoint { + GET, + GET_ID, + GET_ID_EPIC_SUBTASKS, + POST, + POST_ID, + DELETE, + DELETE_ID, + UNKNOWN +} \ No newline at end of file diff --git a/src/ExceptionHandler.java b/src/ExceptionHandler.java new file mode 100644 index 0000000..f640361 --- /dev/null +++ b/src/ExceptionHandler.java @@ -0,0 +1,27 @@ +import com.sun.net.httpserver.Filter; +import com.sun.net.httpserver.HttpExchange; + +import java.io.IOException; + +public class ExceptionHandler extends Filter { + @Override + public void doFilter(HttpExchange exchange, Chain chain) throws IOException { + try { + chain.doFilter(exchange); + } catch (NotFoundException e) { + BaseHttpHandler.sendNotFound(exchange, e.getMessage()); + } catch (TaskOverlapsException e) { + BaseHttpHandler.sendHasInteractions(exchange, e.getMessage()); + } catch (Exception e) { + String message = "Внутренняя ошибка сервера: " + e.getClass().getSimpleName(); + BaseHttpHandler.sendIntervalServerError(exchange, message); + e.printStackTrace(); + } + } + + @Override + public String description() { + return "Обработчик исключений"; + } + +} diff --git a/src/HttpEpicsController.java b/src/HttpEpicsController.java new file mode 100644 index 0000000..824b199 --- /dev/null +++ b/src/HttpEpicsController.java @@ -0,0 +1,53 @@ +import com.google.gson.Gson; +import com.sun.net.httpserver.HttpExchange; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +public class HttpEpicsController extends BaseHttpHandler { + + public HttpEpicsController(TaskManager taskManager, Gson gson) { + super(taskManager, gson); + } + + @Override + public void handle(HttpExchange exchange) throws IOException { + String[] pathParts = exchange.getRequestURI().getPath().split("/"); + String requestMethod = exchange.getRequestMethod(); + + Endpoint endpoint = getEndpoint(pathParts, requestMethod); + switch (endpoint) { + case GET: + sendText(exchange, gson.toJson(taskManager.getAllEpics())); + case GET_ID: + sendText(exchange, gson.toJson(taskManager.getEpicByID(Integer.parseInt(pathParts[2])))); + case GET_ID_EPIC_SUBTASKS: + sendText(exchange, gson.toJson(taskManager.getSubtaskListByEpicId(Integer.parseInt(pathParts[2])))); + case POST: { + String body = new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8); + taskManager.addEpic(gson.fromJson(body, Epic.class)); + sendSuccessfullyModified(exchange, "Эпик успешно добавлен"); + break; + } + case POST_ID: { + String body = new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8); + taskManager.updateEpicByID(gson.fromJson(body, Epic.class)); + sendSuccessfullyModified(exchange, "Эпик успешно обнолен"); + break; + } + case DELETE: { + taskManager.deleteAllEpic(); + sendText(exchange, "Все эпики удалены"); + break; + } + case DELETE_ID: { + taskManager.deleteEpicByID(Integer.parseInt(pathParts[2])); + sendText(exchange, "Эпик с идентификатором " + Integer.parseInt(pathParts[2]) + " удален"); + break; + } + default: + throw new RuntimeException("Эндпоинт не найден: " + requestMethod + " " + exchange.getRequestURI().getPath()); + } + } + +} diff --git a/src/HttpHistoryController.java b/src/HttpHistoryController.java new file mode 100644 index 0000000..5309fa8 --- /dev/null +++ b/src/HttpHistoryController.java @@ -0,0 +1,26 @@ +import com.google.gson.Gson; +import com.sun.net.httpserver.HttpExchange; + +import java.io.IOException; + +public class HttpHistoryController extends BaseHttpHandler { + + public HttpHistoryController(TaskManager taskManager, Gson gson) { + super(taskManager, gson); + } + + @Override + public void handle(HttpExchange exchange) throws IOException { + String[] pathParts = exchange.getRequestURI().getPath().split("/"); + String requestMethod = exchange.getRequestMethod(); + + Endpoint endpoint = getEndpoint(pathParts, requestMethod); + switch (endpoint) { + case GET: + sendText(exchange, gson.toJson(taskManager.getHistory())); + default: + throw new RuntimeException("Эндпоинт не найден: " + requestMethod + " " + exchange.getRequestURI().getPath()); + } + } + +} diff --git a/src/HttpPrioritizedController.java b/src/HttpPrioritizedController.java new file mode 100644 index 0000000..fcba916 --- /dev/null +++ b/src/HttpPrioritizedController.java @@ -0,0 +1,26 @@ +import com.google.gson.Gson; +import com.sun.net.httpserver.HttpExchange; + +import java.io.IOException; + +public class HttpPrioritizedController extends BaseHttpHandler { + + public HttpPrioritizedController(TaskManager taskManager, Gson gson) { + super(taskManager, gson); + } + + @Override + public void handle(HttpExchange exchange) throws IOException { + String[] pathParts = exchange.getRequestURI().getPath().split("/"); + String requestMethod = exchange.getRequestMethod(); + + Endpoint endpoint = getEndpoint(pathParts, requestMethod); + switch (endpoint) { + case GET: + sendText(exchange, gson.toJson(taskManager.getPrioritizedTasks())); + default: + throw new RuntimeException("Эндпоинт не найден: " + requestMethod + " " + exchange.getRequestURI().getPath()); + } + } + +} diff --git a/src/HttpSubtasksController.java b/src/HttpSubtasksController.java new file mode 100644 index 0000000..d75bd0d --- /dev/null +++ b/src/HttpSubtasksController.java @@ -0,0 +1,52 @@ +import com.google.gson.Gson; +import com.sun.net.httpserver.HttpExchange; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +public class HttpSubtasksController extends BaseHttpHandler { + + public HttpSubtasksController(TaskManager taskManager, Gson gson) { + super(taskManager, gson); + } + + @Override + public void handle(HttpExchange exchange) throws IOException { + String[] pathParts = exchange.getRequestURI().getPath().split("/"); + String requestMethod = exchange.getRequestMethod(); + + Endpoint endpoint = getEndpoint(pathParts, requestMethod); + switch (endpoint) { + case GET: + sendText(exchange, gson.toJson(taskManager.getAllSubtasks())); + case GET_ID: + sendText(exchange, gson.toJson(taskManager.getSubtaskByID(Integer.parseInt(pathParts[2])))); + case POST: { + String body = new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8); + Subtask subtask = gson.fromJson(body, Subtask.class); + taskManager.addSubtask(subtask.getEpicId(), subtask); + sendSuccessfullyModified(exchange, "Подзадача успешно добавлена"); + break; + } + case POST_ID: { + String body = new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8); + taskManager.updateSubtaskByID(gson.fromJson(body, Subtask.class)); + sendSuccessfullyModified(exchange, "Подзадача успешно обнолена"); + break; + } + case DELETE: { + taskManager.deleteAllSubtasks(); + sendText(exchange, "Все подзадачи удалены"); + break; + } + case DELETE_ID: { + taskManager.deleteSubtaskByID(Integer.parseInt(pathParts[2])); + sendText(exchange, "Подзадача с идентификатором " + Integer.parseInt(pathParts[2]) + " удалена"); + break; + } + default: + throw new RuntimeException("Эндпоинт не найден: " + requestMethod + " " + exchange.getRequestURI().getPath()); + } + } + +} diff --git a/src/HttpTaskServer.java b/src/HttpTaskServer.java new file mode 100644 index 0000000..4ee09e2 --- /dev/null +++ b/src/HttpTaskServer.java @@ -0,0 +1,52 @@ +import java.io.IOException; + +import com.sun.net.httpserver.Filter; +import com.sun.net.httpserver.HttpServer; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import java.net.InetSocketAddress; +import java.time.Duration; +import java.time.LocalDateTime; + +public class HttpTaskServer { + + private final HttpServer httpServer; + private final TaskManager taskManager; + private final Gson gson; + + public HttpTaskServer(TaskManager taskManager) throws IOException { + this.httpServer = HttpServer.create(new InetSocketAddress(8080), 0); + this.taskManager = taskManager; + this.gson = new GsonBuilder() + .registerTypeAdapter(LocalDateTime.class, new LocalDateTimeAdapter()) + .registerTypeAdapter(Duration.class, new DurationAdapter()) + .create(); + } + + public static void main(String[] args) throws IOException { + HttpTaskServer httpTaskServer = new HttpTaskServer(Managers.getDefault()); + httpTaskServer.start(); + } + + public void start() { + + Filter filter = new ExceptionHandler(); + httpServer.createContext("/tasks", new HttpTasksController(taskManager, gson)).getFilters().add(filter); + httpServer.createContext("/subtasks", new HttpSubtasksController(taskManager, gson)).getFilters().add(filter); + httpServer.createContext("/epics", new HttpEpicsController(taskManager, gson)).getFilters().add(filter); + httpServer.createContext("/history", new HttpHistoryController(taskManager, gson)).getFilters().add(filter); + httpServer.createContext("/prioritized", new HttpPrioritizedController(taskManager, gson)).getFilters().add(filter); + + httpServer.start(); + } + + public void stop() { + httpServer.stop(0); + } + + public Gson getGson() { + return gson; + } + +} diff --git a/src/HttpTasksController.java b/src/HttpTasksController.java new file mode 100644 index 0000000..76bf739 --- /dev/null +++ b/src/HttpTasksController.java @@ -0,0 +1,51 @@ +import com.google.gson.Gson; +import com.sun.net.httpserver.HttpExchange; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +public class HttpTasksController extends BaseHttpHandler { + + public HttpTasksController(TaskManager taskManager, Gson gson) { + super(taskManager, gson); + } + + @Override + public void handle(HttpExchange exchange) throws IOException { + String[] pathParts = exchange.getRequestURI().getPath().split("/"); + String requestMethod = exchange.getRequestMethod(); + + Endpoint endpoint = getEndpoint(pathParts, requestMethod); + switch (endpoint) { + case GET: + sendText(exchange, gson.toJson(taskManager.getAllTasks())); + case GET_ID: + sendText(exchange, gson.toJson(taskManager.getTaskByID(Integer.parseInt(pathParts[2])))); + case POST: { + String body = new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8); + taskManager.addTask(gson.fromJson(body, Task.class)); + sendSuccessfullyModified(exchange, "Задача успешно добавлена"); + break; + } + case POST_ID: { + String body = new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8); + taskManager.updateTaskByID(gson.fromJson(body, Task.class)); + sendSuccessfullyModified(exchange, "Задача успешно обнолена"); + break; + } + case DELETE: { + taskManager.deleteAllTask(); + sendText(exchange, "Все задачи удалены"); + break; + } + case DELETE_ID: { + taskManager.deleteTaskByID(Integer.parseInt(pathParts[2])); + sendText(exchange, "Задача с идентификатором " + Integer.parseInt(pathParts[2]) + " удалена"); + break; + } + default: + throw new RuntimeException("Эндпоинт не найден: " + requestMethod + " " + exchange.getRequestURI().getPath()); + } + } + +} \ No newline at end of file diff --git a/src/InMemoryTaskManager.java b/src/InMemoryTaskManager.java index a4db51e..e89835a 100644 --- a/src/InMemoryTaskManager.java +++ b/src/InMemoryTaskManager.java @@ -32,8 +32,12 @@ public InMemoryTaskManager(HashMap tasks, HashMap public void addTask(Task task) { Task newTask = new Task(generateId(), task.getTitle(), task.getDescription(), task.getStatus(), task.getStartTime(), task.getDuration()); this.tasks.put(newTask.getId(), newTask); - if (newTask.getStartTime() != null && newTask.getEndTime() != null && !isOverlapTasksInTime(newTask)) { - addTaskInPriorityList(newTask); + if (newTask.getStartTime() != null && newTask.getEndTime() != null) { + if (!isOverlapTasksInTime(newTask)) { + addTaskInPriorityList(newTask); + } else { + throw new TaskOverlapsException("Задача пересекается по времени"); + } } } @@ -45,7 +49,11 @@ public ArrayList getAllTasks() { @Override public Task getTaskByID(int id) { Task task = tasks.get(id); - historyManager.add(task); + if (task == null) { + throw new NotFoundException("Задача с идентификатором " + id + " не найдена"); + } else { + historyManager.add(task); + } return task; } @@ -55,7 +63,11 @@ public void deleteTaskByID(int id) { if (tasks.containsKey(id)) { deleteTaskFromPriorityList(tasks.get(id)); tasks.remove(id); + } else { + throw new NotFoundException("Задача с идентификатором " + id + " не найдена"); } + } else { + throw new NotFoundException("Идентификатор задачи должен быть больше 0"); } } @@ -69,11 +81,19 @@ public void deleteAllTask() { public void updateTaskByID(Task task) { if (task.getId() >= 1) { if (tasks.containsKey(task.getId())) { - if (task.getStartTime() != null && task.getEndTime() != null && !isOverlapTasksInTime(task)) { - updatePriorityList(tasks.get(task.getId()), task); - } tasks.put(task.getId(), task); + if (task.getStartTime() != null && task.getEndTime() != null) { + if (!isOverlapTasksInTime(task)) { + updatePriorityList(tasks.get(task.getId()), task); + } else { + throw new TaskOverlapsException("Задача пересекается по времени"); + } + } + } else { + throw new NotFoundException("Задача с идентификатором " + task.getId() + " не найдена"); } + } else { + throw new NotFoundException("Идентификатор задачи должен быть больше 0"); } } @@ -91,34 +111,52 @@ public ArrayList getAllEpics() { @Override public Epic getEpicByID(int id) { - Epic epic = null; - if (id >= 1 && epics.containsKey(id)) { - epic = epics.get(id); + Epic epic; + if (id >= 1) { + if (epics.containsKey(id)) { + epic = epics.get(id); + historyManager.add(epic); + } else { + throw new NotFoundException("Эпик с идентификатором " + id + " не найден"); + } + } else { + throw new NotFoundException("Идентификатор эпика должен быть больше 0"); } - historyManager.add(epic); return epic; } @Override public void deleteEpicByID(int id) { - if (id >= 1 && epics.containsKey(id)) { - Epic oldEpic = epics.get(id); - List oldSubtaskId = oldEpic.getSubtaskIdList(); - - oldSubtaskId.stream().forEach(subtaskId -> { - deleteTaskFromPriorityList(subtasks.get(subtaskId)); - subtasks.remove(subtaskId); - }); - epics.remove(id); + if (id >= 1) { + if (epics.containsKey(id)) { + Epic oldEpic = epics.get(id); + List oldSubtaskId = oldEpic.getSubtaskIdList(); + + oldSubtaskId.stream().forEach(subtaskId -> { + deleteTaskFromPriorityList(subtasks.get(subtaskId)); + subtasks.remove(subtaskId); + }); + epics.remove(id); + } else { + throw new NotFoundException("Эпик с идентификатором " + id + " не найден"); + } + } else { + throw new NotFoundException("Идентификатор эпика должен быть больше 0"); } } @Override public void updateEpicByID(Epic epic) { - if (epic.getId() >= 1 && epics.containsKey(epic.getId())) { - Epic oldTask = epics.get(epic.getId()); - oldTask.setTitle(epic.getTitle()); - oldTask.setDescription(epic.getDescription()); + if (epic.getId() >= 1) { + if (epics.containsKey(epic.getId())) { + Epic oldTask = epics.get(epic.getId()); + oldTask.setTitle(epic.getTitle()); + oldTask.setDescription(epic.getDescription()); + } else { + throw new NotFoundException("Эпик с идентификатором " + epic.getId() + " не найден"); + } + } else { + throw new NotFoundException("Идентификатор эпика должен быть больше 0"); } } @@ -133,15 +171,25 @@ public void deleteAllEpic() { // Все методы для подзадач @Override public void addSubtask(int epicId, Subtask subtask) { - if (epicId >= 1 && epics.containsKey(epicId)) { - Subtask newSubtask = new Subtask(generateId(), subtask.getTitle(), subtask.getDescription(), subtask.getStatus(), epicId, subtask.getStartTime(), subtask.getDuration()); - this.subtasks.put(newSubtask.getId(), newSubtask); - if (newSubtask.getStartTime() != null && newSubtask.getEndTime() != null && !isOverlapTasksInTime(newSubtask)) { - addTaskInPriorityList(newSubtask); + if (epicId >= 1) { + if (epics.containsKey(epicId)) { + Subtask newSubtask = new Subtask(generateId(), subtask.getTitle(), subtask.getDescription(), subtask.getStatus(), epicId, subtask.getStartTime(), subtask.getDuration()); + this.subtasks.put(newSubtask.getId(), newSubtask); + if (newSubtask.getStartTime() != null && newSubtask.getEndTime() != null) { + if (!isOverlapTasksInTime(newSubtask)) { + addTaskInPriorityList(newSubtask); + } else { + throw new TaskOverlapsException("Подзадача пересекается по времени"); + } + } + epics.get(epicId).getSubtaskIdList().add(newSubtask.getId()); + updateStatusEpic(epicId); + updateTimeExecutionEpic(epicId); + } else { + throw new NotFoundException("Эпик с идентификатором " + epicId + " не найден для добавления подзадачи"); } - epics.get(epicId).getSubtaskIdList().add(newSubtask.getId()); - updateStatusEpic(epicId); - updateTimeExecutionEpic(epicId); + } else { + throw new NotFoundException("Идентификатор эпика у подзадачи должен быть больше 0"); } } @@ -152,43 +200,75 @@ public ArrayList getAllSubtasks() { @Override public Subtask getSubtaskByID(int id) { - Subtask subtask = null; - if (id >= 1 && subtasks.containsKey(id)) { - subtask = subtasks.get(id); + Subtask subtask; + if (id >= 1) { + if (subtasks.containsKey(id)) { + subtask = subtasks.get(id); + historyManager.add(subtask); + } else { + throw new NotFoundException("Подзадача с идентификатором " + id + " не найдена"); + } + } else { + throw new NotFoundException("Идентификатор подзадачи должен быть больше 0"); } - historyManager.add(subtask); return subtask; } @Override public void deleteSubtaskByID(int id) { - if (id >= 1 && subtasks.containsKey(id)) { - Subtask subtask = subtasks.get(id); - deleteSubtaskIdEpic(subtask.getId(), subtask.getEpicId()); - deleteTaskFromPriorityList(subtask); - subtasks.remove(id); + if (id >= 1) { + if (subtasks.containsKey(id)) { + Subtask subtask = subtasks.get(id); + deleteSubtaskIdEpic(subtask.getId(), subtask.getEpicId()); + deleteTaskFromPriorityList(subtask); + subtasks.remove(id); + } else { + throw new NotFoundException("Подзадача с идентификатором " + id + " не найдена"); + } + } else { + throw new NotFoundException("Идентификатор подзадачи должен быть больше 0"); } } @Override public void updateSubtaskByID(Subtask subtask) { - if (subtask.getId() >= 1 && subtask.getEpicId() >= 1 && subtasks.containsKey(subtask.getId()) && epics.containsKey(subtask.getEpicId())) { - if (subtask.getStartTime() != null && subtask.getEndTime() != null && !isOverlapTasksInTime(subtask)) { - updatePriorityList(subtasks.get(subtask.getId()), subtask); + if (subtask.getId() >= 1 && subtask.getEpicId() >= 1) { + if (subtasks.containsKey(subtask.getId())) { + if (epics.containsKey(subtask.getEpicId())) { + if (subtask.getStartTime() != null && subtask.getEndTime() != null) { + if (!isOverlapTasksInTime(subtask)) { + updatePriorityList(subtasks.get(subtask.getId()), subtask); + } else { + throw new TaskOverlapsException("Подзадача пересекается по времени"); + } + } + subtasks.put(subtask.getId(), subtask); + updateStatusEpic(subtask.getEpicId()); + updateTimeExecutionEpic(subtask.getEpicId()); + } else { + throw new NotFoundException("Эпик с идентификатором " + subtask.getEpicId() + " не найден"); + } + } else { + throw new NotFoundException("Подзадача с идентификатором " + subtask.getId() + " не найдена"); } - subtasks.put(subtask.getId(), subtask); - updateStatusEpic(subtask.getEpicId()); - updateTimeExecutionEpic(subtask.getEpicId()); + } else { + throw new NotFoundException("Идентификаторы эпика и подзадачи должны быть больше 0"); } } @Override public List getSubtaskListByEpicId(int epicId) { - List newSubtask = new ArrayList<>(); - if (epicId >= 1 && epics.containsKey(epicId)) { - Epic oldEpic = epics.get(epicId); - List oldSubtaskId = oldEpic.getSubtaskIdList(); - newSubtask = oldSubtaskId.stream().map(subtasks::get).collect(Collectors.toList()); + List newSubtask; + if (epicId >= 1) { + if (epics.containsKey(epicId)) { + Epic oldEpic = epics.get(epicId); + List oldSubtaskId = oldEpic.getSubtaskIdList(); + newSubtask = oldSubtaskId.stream().map(subtasks::get).collect(Collectors.toList()); + } else { + throw new NotFoundException("Эпик с идентификатором " + epicId + " не найден"); + } + } else { + throw new NotFoundException("Идентификатор эпика должен быть больше 0"); } return newSubtask; } @@ -220,15 +300,23 @@ public List getHistory() { return historyManager.getHistory(); } + public void setNewId(int newId) { + this.newId = newId; + } + // Приватные методы вынес вниз класса private boolean isOverlapTasksInTime(Task task) { - return prioritizedTasks.stream().anyMatch(priorityTask -> { - if (priorityTask.getStartTime() != null && priorityTask.getEndTime() != null && task.getStartTime() != null && task.getEndTime() != null) { - return priorityTask.getEndTime().isAfter(task.getStartTime()) && task.getEndTime().isAfter(priorityTask.getStartTime()); - } else { - return false; - } - }); + return prioritizedTasks.stream() + .filter(t -> !t.equals(task)) + .anyMatch(priorityTask -> { + if (priorityTask.getStartTime() != null && priorityTask.getEndTime() != null && + task.getStartTime() != null && task.getEndTime() != null) { + return priorityTask.getEndTime().isAfter(task.getStartTime()) && + task.getEndTime().isAfter(priorityTask.getStartTime()); + } else { + return false; + } + }); } private void addTaskInPriorityList(Task task) { diff --git a/src/LocalDateTimeAdapter.java b/src/LocalDateTimeAdapter.java new file mode 100644 index 0000000..43942e5 --- /dev/null +++ b/src/LocalDateTimeAdapter.java @@ -0,0 +1,28 @@ +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public class LocalDateTimeAdapter extends TypeAdapter { + private static final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + + @Override + public void write(final JsonWriter jsonWriter, final LocalDateTime localDateTime) throws IOException { + if (localDateTime == null) { + jsonWriter.nullValue(); + } else { + jsonWriter.value(dtf.format(localDateTime)); + } + } + + @Override + public LocalDateTime read(final JsonReader jsonReader) throws IOException { + if (jsonReader == null) { + return null; + } + return LocalDateTime.parse(jsonReader.nextString(), dtf); + } +} \ No newline at end of file diff --git a/src/Managers.java b/src/Managers.java index 8693176..48026a5 100644 --- a/src/Managers.java +++ b/src/Managers.java @@ -8,4 +8,4 @@ public static HistoryManager getDefaultHistory() { return new InMemoryHistoryManager(); } -} +} \ No newline at end of file diff --git a/src/NotFoundException.java b/src/NotFoundException.java new file mode 100644 index 0000000..f45067d --- /dev/null +++ b/src/NotFoundException.java @@ -0,0 +1,5 @@ +public class NotFoundException extends RuntimeException { + public NotFoundException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/src/TaskManager.java b/src/TaskManager.java index 7ae59a1..c881f8c 100644 --- a/src/TaskManager.java +++ b/src/TaskManager.java @@ -50,4 +50,5 @@ public interface TaskManager { List getPrioritizedTasks(); + void setNewId(int i); } diff --git a/src/TaskOverlapsException.java b/src/TaskOverlapsException.java new file mode 100644 index 0000000..416f065 --- /dev/null +++ b/src/TaskOverlapsException.java @@ -0,0 +1,5 @@ +public class TaskOverlapsException extends RuntimeException { + public TaskOverlapsException(String message) { + super(message); + } +} diff --git a/test/HttpTaskServerEpicsTest.java b/test/HttpTaskServerEpicsTest.java new file mode 100644 index 0000000..dc46256 --- /dev/null +++ b/test/HttpTaskServerEpicsTest.java @@ -0,0 +1,253 @@ +import com.google.gson.Gson; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +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 java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class HttpTaskServerEpicsTest { + private static TaskManager taskManager; + private static HttpTaskServer httpTaskServer; + private static Gson gson; + private static HttpClient httpClient; + + @BeforeAll + static void beforeAll() throws IOException { + taskManager = Managers.getDefault(); + httpTaskServer = new HttpTaskServer(taskManager); + gson = httpTaskServer.getGson(); + httpTaskServer.start(); + httpClient = HttpClient.newHttpClient(); + } + + @AfterAll + static void afterAll() { + httpTaskServer.stop(); + httpClient.close(); + } + + @BeforeEach + void beforeEach() { + taskManager.deleteAllTask(); + taskManager.deleteAllEpic(); + taskManager.setNewId(1); + } + + @Test + void testReturnAllEpics() throws IOException, InterruptedException { + Epic epic1 = new Epic(1, "Заголовок эпика 1", "Подробное описание эпика 1", Status.NEW); + taskManager.addEpic(epic1); + + String epic1Json = gson.toJson(epic1); + + URI url = URI.create("http://localhost:8080/epics"); + HttpRequest request = HttpRequest + .newBuilder() + .uri(url) + .GET() + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + String responseBody = response.body(); + + assertEquals(200, response.statusCode(), "Неверный код ответа сервера"); + assertTrue(responseBody.contains(epic1Json), "Нет добавленного эпика в теле ответа сервера"); + + taskManager.deleteAllEpic(); + + HttpResponse responseNew = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + String responseBodyNew = responseNew.body(); + + assertEquals(200, responseNew.statusCode(), "Неверный код ответа сервера после удаления всех эпиков"); + assertEquals("[]", responseBodyNew, "Тело ответа сервера не пустое после удаления всех эпиков"); + } + + @Test + void testReturnEpicById() throws IOException, InterruptedException { + Epic epic1 = new Epic(1, "Заголовок эпика 1", "Подробное описание эпика 1", Status.NEW); + taskManager.addEpic(epic1); + + String epic1Json = gson.toJson(epic1); + + URI url = URI.create("http://localhost:8080/epics/1"); + HttpRequest request = HttpRequest + .newBuilder() + .uri(url) + .GET() + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + String responseBody = response.body(); + + assertEquals(200, response.statusCode(), "Неверный код ответа сервера"); + assertTrue(responseBody.contains(epic1Json), "Нет добавленного эпика в теле ответа сервера"); + + taskManager.deleteAllEpic(); + + HttpResponse responseNew = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + String responseBodyNew = responseNew.body(); + + assertEquals(404, responseNew.statusCode(), "Неверный код ответа сервера после удаления всех эпиков"); + assertEquals("Эпик с идентификатором 1 не найден", responseBodyNew, "Тело ответа сервера не пустое после удаления всех эпиков"); + } + + @Test + void testReturnSubtasksForEpicById() throws IOException, InterruptedException { + Epic epic1 = new Epic(1, "Заголовок эпика 1", "Подробное описание эпика 1", Status.NEW); + taskManager.addEpic(epic1); + + LocalDateTime expectedStartTime1 = LocalDateTime.of(2025, 4, 27, 23, 7); + Duration expectedDuration1 = Duration.ofMinutes(300); + Subtask subtask1 = new Subtask(2, "Подзадача 1 эпика 1", "описание подзадачи 1 эпика 1", 1, expectedStartTime1, expectedDuration1); + taskManager.addSubtask(1, subtask1); + + LocalDateTime expectedStartTime2 = LocalDateTime.of(2025, 4, 28, 23, 7); + Duration expectedDuration2 = Duration.ofMinutes(300); + Subtask subtask2 = new Subtask(3, "Подзадача 2 эпика 1", "описание подзадачи 2 эпика 1", 1, expectedStartTime2, expectedDuration2); + taskManager.addSubtask(1, subtask2); + + String subtask1Json = gson.toJson(subtask1); + String subtask2Json = gson.toJson(subtask2); + + URI url = URI.create("http://localhost:8080/epics/1/subtasks"); + HttpRequest request = HttpRequest + .newBuilder() + .uri(url) + .GET() + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + String responseBody = response.body(); + + assertEquals(200, response.statusCode(), "Неверный код ответа сервера"); + assertTrue(responseBody.contains(subtask1Json), "Нет добавленной подзадачи 1 в теле ответа сервера"); + assertTrue(responseBody.contains(subtask2Json), "Нет добавленной подзадачи 2 в теле ответа сервера"); + + taskManager.deleteAllEpic(); + + HttpResponse responseNew = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + String responseBodyNew = responseNew.body(); + + assertEquals(404, responseNew.statusCode(), "Неверный код ответа сервера после удаления всех эпиков"); + assertEquals("Эпик с идентификатором 1 не найден", responseBodyNew, "Тело ответа сервера не пустое после удаления всех эпиков"); + } + + @Test + void testAddEpic() throws IOException, InterruptedException { + Epic epic1 = new Epic(1, "Заголовок эпика 1", "Подробное описание эпика 1", Status.NEW); + + String epic1Json = gson.toJson(epic1); + + URI url = URI.create("http://localhost:8080/epics"); + HttpRequest request = HttpRequest + .newBuilder() + .uri(url) + .POST(HttpRequest.BodyPublishers.ofString(epic1Json)) + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(201, response.statusCode(), "Неверный код ответа сервера"); + + List tasksFromManager = taskManager.getAllEpics(); + + assertNotNull(tasksFromManager, "Эпики не возвращаются"); + assertEquals(1, tasksFromManager.size(), "Некорректное количество эпиков"); + assertEquals("Заголовок эпика 1", tasksFromManager.getFirst().getTitle(), "Некорректное имя эпика"); + } + + @Test + void testUpdateEpicById() throws IOException, InterruptedException { + Epic epic1 = new Epic(1, "Заголовок эпика 1", "Подробное описание эпика 1", Status.NEW); + taskManager.addEpic(epic1); + + Epic epic1Update = new Epic(1, "Заголовок эпика 1 изменен", "Подробное описание эпика 1 изменено", Status.NEW); + + String epic1UpdateJson = gson.toJson(epic1Update); + + URI url = URI.create("http://localhost:8080/epics/1"); + HttpRequest request = HttpRequest + .newBuilder() + .uri(url) + .POST(HttpRequest.BodyPublishers.ofString(epic1UpdateJson)) + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(201, response.statusCode(), "Неверный код ответа сервера"); + + List tasksFromManager = taskManager.getAllEpics(); + + assertNotNull(tasksFromManager, "Эпики не возвращаются"); + assertEquals(1, tasksFromManager.size(), "Некорректное количество эпиков"); + assertEquals("Заголовок эпика 1 изменен", tasksFromManager.getFirst().getTitle(), "Имя эпика не обновилось"); + assertEquals("Подробное описание эпика 1 изменено", tasksFromManager.getFirst().getDescription(), "Описание эпика не обновилось"); + + Epic epic2Update = new Epic(2, "Заголовок эпика 1 изменен", "Подробное описание эпика 1 изменено", Status.NEW); + + String epic2UpdateJson = gson.toJson(epic2Update); + + URI urlNew = URI.create("http://localhost:8080/epics/2"); + HttpRequest requestNew = HttpRequest + .newBuilder() + .uri(urlNew) + .POST(HttpRequest.BodyPublishers.ofString(epic2UpdateJson)) + .build(); + + HttpResponse responseNew = httpClient.send(requestNew, HttpResponse.BodyHandlers.ofString()); + assertEquals(404, responseNew.statusCode(), "Неверный код ответа сервера"); + } + + @Test + void testDeleteAllEpics() throws IOException, InterruptedException { + Epic epic1 = new Epic(1, "Заголовок эпика 1", "Подробное описание эпика 1", Status.NEW); + taskManager.addEpic(epic1); + + URI url = URI.create("http://localhost:8080/epics"); + HttpRequest request = HttpRequest + .newBuilder() + .uri(url) + .DELETE() + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode(), "Неверный код ответа сервера"); + assertTrue(taskManager.getAllEpics().isEmpty(), "Не все эпики удалены"); + } + + @Test + void testDeleteEpicById() throws IOException, InterruptedException { + Epic epic1 = new Epic(1, "Заголовок эпика 1", "Подробное описание эпика 1", Status.NEW); + taskManager.addEpic(epic1); + + URI url = URI.create("http://localhost:8080/epics/2"); + HttpRequest request = HttpRequest + .newBuilder() + .uri(url) + .DELETE() + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(404, response.statusCode(), "Неверный код ответа сервера"); + + URI urlNew = URI.create("http://localhost:8080/epics/1"); + HttpRequest requestNew = HttpRequest + .newBuilder() + .uri(urlNew) + .DELETE() + .build(); + + HttpResponse responseNew = httpClient.send(requestNew, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, responseNew.statusCode(), "Неверный код ответа сервера"); + assertTrue(taskManager.getAllEpics().isEmpty(), "Эпик 1 не удален"); + } + +} diff --git a/test/HttpTaskServerHistoryTest.java b/test/HttpTaskServerHistoryTest.java new file mode 100644 index 0000000..80dfcac --- /dev/null +++ b/test/HttpTaskServerHistoryTest.java @@ -0,0 +1,99 @@ +import com.google.gson.Gson; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +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 HttpTaskServerHistoryTest { + private static TaskManager taskManager; + private static HttpTaskServer httpTaskServer; + private static Gson gson; + private static HttpClient httpClient; + + @BeforeAll + static void beforeAll() throws IOException { + taskManager = Managers.getDefault(); + httpTaskServer = new HttpTaskServer(taskManager); + gson = httpTaskServer.getGson(); + httpTaskServer.start(); + httpClient = HttpClient.newHttpClient(); + } + + @AfterAll + static void afterAll() { + httpTaskServer.stop(); + httpClient.close(); + } + + @BeforeEach + void beforeEach() { + taskManager.deleteAllTask(); + taskManager.deleteAllEpic(); + taskManager.setNewId(1); + } + + @Test + void testReturnAllTypesTasksInHistory() throws IOException, InterruptedException { + LocalDateTime expectedStartTime1 = LocalDateTime.of(2025, 4, 25, 23, 7); + Duration expectedDuration1 = Duration.ofMinutes(150); + Task task1 = new Task(1, "Задача 1", "описание задачи 1", expectedStartTime1, expectedDuration1); + taskManager.addTask(task1); + + Epic epic1 = new Epic(2, "Заголовок эпика 1", "Подробное описание эпика 1", Status.NEW); + taskManager.addEpic(epic1); + + LocalDateTime expectedStartTime2 = LocalDateTime.of(2025, 4, 27, 23, 7); + Duration expectedDuration2 = Duration.ofMinutes(300); + Subtask subtask1 = new Subtask(3, "Подзадача 1 эпика 1", "описание подзадачи 1 эпика 1", 2, expectedStartTime2, expectedDuration2); + taskManager.addSubtask(2, subtask1); + + URI urlTask = URI.create("http://localhost:8080/tasks/1"); + HttpRequest requestTask = HttpRequest + .newBuilder() + .uri(urlTask) + .GET() + .build(); + httpClient.send(requestTask, HttpResponse.BodyHandlers.ofString()); + + URI urlEpic = URI.create("http://localhost:8080/epics/2"); + HttpRequest requestEpic = HttpRequest + .newBuilder() + .uri(urlEpic) + .GET() + .build(); + httpClient.send(requestEpic, HttpResponse.BodyHandlers.ofString()); + + URI urlSubtask = URI.create("http://localhost:8080/subtasks/3"); + HttpRequest requestSubtask = HttpRequest + .newBuilder() + .uri(urlSubtask) + .GET() + .build(); + httpClient.send(requestSubtask, HttpResponse.BodyHandlers.ofString()); + + URI urlHistory = URI.create("http://localhost:8080/history"); + HttpRequest requestHistory = HttpRequest + .newBuilder() + .uri(urlHistory) + .GET() + .build(); + HttpResponse responseHistory = httpClient.send(requestHistory, HttpResponse.BodyHandlers.ofString()); + String bodyHistory = responseHistory.body(); + + assertEquals(200, responseHistory.statusCode(), "Неверный код ответа сервера"); + assertTrue(bodyHistory.contains(gson.toJson(task1)), "Нет просмотренной задачи в теле ответа сервера"); + assertTrue(bodyHistory.contains(gson.toJson(taskManager.getEpicByID(2))), "Нет просмотренного эпика в теле ответа сервера"); + assertTrue(bodyHistory.contains(gson.toJson(subtask1)), "Нет просмотренной подзадачи в теле ответа сервера"); + } + +} \ No newline at end of file diff --git a/test/HttpTaskServerPrioritizedTest.java b/test/HttpTaskServerPrioritizedTest.java new file mode 100644 index 0000000..f9d952d --- /dev/null +++ b/test/HttpTaskServerPrioritizedTest.java @@ -0,0 +1,83 @@ +import com.google.gson.Gson; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +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 HttpTaskServerPrioritizedTest { + private static TaskManager taskManager; + private static HttpTaskServer httpTaskServer; + private static Gson gson; + private static HttpClient httpClient; + + @BeforeAll + static void beforeAll() throws IOException { + taskManager = Managers.getDefault(); + httpTaskServer = new HttpTaskServer(taskManager); + gson = httpTaskServer.getGson(); + httpTaskServer.start(); + httpClient = HttpClient.newHttpClient(); + } + + @AfterAll + static void afterAll() { + httpTaskServer.stop(); + httpClient.close(); + } + + @BeforeEach + void beforeEach() { + taskManager.deleteAllTask(); + taskManager.deleteAllEpic(); + taskManager.setNewId(1); + } + + @Test + void testReturnCorrectSequenceTasksInPriorityList() throws IOException, InterruptedException { + LocalDateTime expectedStartTime1 = LocalDateTime.of(2025, 4, 25, 23, 7); + Duration expectedDuration1 = Duration.ofMinutes(150); + Task task1 = new Task(1, "Задача 1", "описание задачи 1", expectedStartTime1, expectedDuration1); + taskManager.addTask(task1); + + LocalDateTime expectedStartTime2 = LocalDateTime.of(2025, 4, 24, 23, 7); + Duration expectedDuration2 = Duration.ofMinutes(250); + Task task2 = new Task(2, "Задача 2", "описание задачи 2", expectedStartTime2, expectedDuration2); + taskManager.addTask(task2); + + LocalDateTime expectedStartTime3 = LocalDateTime.of(2025, 4, 26, 23, 7); + Duration expectedDuration3 = Duration.ofMinutes(350); + Task task3 = new Task(3, "Задача 3", "описание задачи 3", expectedStartTime3, expectedDuration3); + taskManager.addTask(task3); + + URI urlPrioritized = URI.create("http://localhost:8080/prioritized"); + HttpRequest requestPrioritized = HttpRequest + .newBuilder() + .uri(urlPrioritized) + .GET() + .build(); + HttpResponse responsePrioritized = httpClient.send(requestPrioritized, HttpResponse.BodyHandlers.ofString()); + String bodyPrioritized = responsePrioritized.body(); + + assertEquals(200, responsePrioritized.statusCode(), "Неверный код ответа сервера"); + assertTrue(bodyPrioritized.contains(gson.toJson(task1)), "Нет задачи 1 в теле ответа сервера"); + assertTrue(bodyPrioritized.contains(gson.toJson(task2)), "Нет задачи 2 в теле ответа сервера"); + assertTrue(bodyPrioritized.contains(gson.toJson(task3)), "Нет задачи 3 в теле ответа сервера"); + + int oneTaskIndex = bodyPrioritized.indexOf(gson.toJson(task2)); + int twoTaskIndex = bodyPrioritized.indexOf(gson.toJson(task1)); + int threeTaskIndex = bodyPrioritized.indexOf(gson.toJson(task3)); + + assertTrue(oneTaskIndex < twoTaskIndex && twoTaskIndex < threeTaskIndex, "Последовательность задач нарушена"); + } + +} \ No newline at end of file diff --git a/test/HttpTaskServerSubtasksTest.java b/test/HttpTaskServerSubtasksTest.java new file mode 100644 index 0000000..4b50cf3 --- /dev/null +++ b/test/HttpTaskServerSubtasksTest.java @@ -0,0 +1,265 @@ +import com.google.gson.Gson; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +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 java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class HttpTaskServerSubtasksTest { + private static TaskManager taskManager; + private static HttpTaskServer httpTaskServer; + private static Gson gson; + private static HttpClient httpClient; + + @BeforeAll + static void beforeAll() throws IOException { + taskManager = Managers.getDefault(); + httpTaskServer = new HttpTaskServer(taskManager); + gson = httpTaskServer.getGson(); + httpTaskServer.start(); + httpClient = HttpClient.newHttpClient(); + } + + @AfterAll + static void afterAll() { + httpTaskServer.stop(); + httpClient.close(); + } + + @BeforeEach + void beforeEach() { + taskManager.deleteAllTask(); + taskManager.deleteAllEpic(); + taskManager.setNewId(1); + } + + @Test + void testReturnAllEpics() throws IOException, InterruptedException { + Epic epic1 = new Epic(1, "Заголовок эпика 1", "Подробное описание эпика 1", Status.NEW); + taskManager.addEpic(epic1); + + LocalDateTime expectedStartTime1 = LocalDateTime.of(2025, 4, 27, 23, 7); + Duration expectedDuration1 = Duration.ofMinutes(300); + Subtask subtask1 = new Subtask(2, "Подзадача 1 эпика 1", "описание подзадачи 1 эпика 1", 1, expectedStartTime1, expectedDuration1); + System.out.println(taskManager.getAllSubtasks()); + taskManager.addSubtask(1, subtask1); + + String subtask1Json = gson.toJson(subtask1); + + URI url = URI.create("http://localhost:8080/subtasks"); + HttpRequest request = HttpRequest + .newBuilder() + .uri(url) + .GET() + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + String responseBody = response.body(); + + assertEquals(200, response.statusCode(), "Неверный код ответа сервера"); + assertTrue(responseBody.contains(subtask1Json), "Нет добавленной подзадачи в теле ответа сервера"); + + taskManager.deleteAllSubtasks(); + + HttpResponse responseNew = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + String responseBodyNew = responseNew.body(); + + assertEquals(200, responseNew.statusCode(), "Неверный код ответа сервера после удаления всех подзадач"); + assertEquals("[]", responseBodyNew, "Тело ответа сервера не пустое после удаления всех подзадач"); + } + + @Test + void testReturnEpicById() throws IOException, InterruptedException { + Epic epic1 = new Epic(1, "Заголовок эпика 1", "Подробное описание эпика 1", Status.NEW); + taskManager.addEpic(epic1); + + LocalDateTime expectedStartTime1 = LocalDateTime.of(2025, 4, 27, 23, 7); + Duration expectedDuration1 = Duration.ofMinutes(300); + Subtask subtask1 = new Subtask(2, "Подзадача 1 эпика 1", "описание подзадачи 1 эпика 1", 1, expectedStartTime1, expectedDuration1); + taskManager.addSubtask(1, subtask1); + + String subtask1Json = gson.toJson(subtask1); + + URI url = URI.create("http://localhost:8080/subtasks/2"); + HttpRequest request = HttpRequest + .newBuilder() + .uri(url) + .GET() + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + String responseBody = response.body(); + + assertEquals(200, response.statusCode(), "Неверный код ответа сервера"); + assertTrue(responseBody.contains(subtask1Json), "Нет добавленной подзадачи в теле ответа сервера"); + + taskManager.deleteAllSubtasks(); + + HttpResponse responseNew = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + String responseBodyNew = responseNew.body(); + + assertEquals(404, responseNew.statusCode(), "Неверный код ответа сервера после удаления всех подзадач"); + assertEquals("Подзадача с идентификатором 2 не найдена", responseBodyNew, "Тело ответа сервера не пустое после удаления всех подзадач"); + } + + @Test + void testAddSubtask() throws IOException, InterruptedException { + Epic epic1 = new Epic(1, "Заголовок эпика 1", "Подробное описание эпика 1", Status.NEW); + taskManager.addEpic(epic1); + + LocalDateTime expectedStartTime1 = LocalDateTime.of(2025, 4, 27, 23, 7); + Duration expectedDuration1 = Duration.ofMinutes(300); + Subtask subtask1 = new Subtask(2, "Подзадача 1 эпика 1", "описание подзадачи 1 эпика 1", 1, expectedStartTime1, expectedDuration1); + + String subtask1Json = gson.toJson(subtask1); + + URI url = URI.create("http://localhost:8080/subtasks"); + + HttpRequest request = HttpRequest + .newBuilder() + .uri(url) + .POST(HttpRequest.BodyPublishers.ofString(subtask1Json)) + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(201, response.statusCode(), "Неверный код ответа сервера"); + + List tasksFromManager = taskManager.getAllSubtasks(); + + assertNotNull(tasksFromManager, "Подзадачи не возвращаются"); + assertEquals(1, tasksFromManager.size(), "Некорректное количество подзадач"); + assertEquals("Подзадача 1 эпика 1", tasksFromManager.getFirst().getTitle(), "Некорректное имя подзадачи"); + } + + @Test + void testUpdateSubtaskById() throws IOException, InterruptedException { + Epic epic1 = new Epic(1, "Заголовок эпика 1", "Подробное описание эпика 1", Status.NEW); + taskManager.addEpic(epic1); + + LocalDateTime expectedStartTime1 = LocalDateTime.of(2025, 4, 27, 23, 7); + Duration expectedDuration1 = Duration.ofMinutes(300); + Subtask subtask1 = new Subtask(2, "Подзадача 1 эпика 1", "описание подзадачи 1 эпика 1", 1, expectedStartTime1, expectedDuration1); + taskManager.addSubtask(1, subtask1); + + Subtask subtask1Update = new Subtask(2, "Подзадача 1 эпика 1 изменена", "описание подзадачи 1 эпика 1 изменено", 1, expectedStartTime1, expectedDuration1); + + String subtask1UpdateJson = gson.toJson(subtask1Update); + + URI url = URI.create("http://localhost:8080/subtasks/2"); + HttpRequest request = HttpRequest + .newBuilder() + .uri(url) + .POST(HttpRequest.BodyPublishers.ofString(subtask1UpdateJson)) + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(201, response.statusCode(), "Неверный код ответа сервера"); + + List tasksFromManager = taskManager.getAllSubtasks(); + + assertNotNull(tasksFromManager, "Подзадачи не возвращаются"); + assertEquals(1, tasksFromManager.size(), "Некорректное количество подзадач"); + assertEquals("Подзадача 1 эпика 1 изменена", tasksFromManager.getFirst().getTitle(), "Имя подзадачи не обновилось"); + assertEquals("описание подзадачи 1 эпика 1 изменено", tasksFromManager.getFirst().getDescription(), "Описание подзадачи не обновилось"); + + Subtask subtask2Update = new Subtask(3, "Подзадача 1 эпика 1 изменена", "описание подзадачи 1 эпика 1 изменено", 1, expectedStartTime1, expectedDuration1); + + String subtask2UpdateJson = gson.toJson(subtask2Update); + + URI urlNew = URI.create("http://localhost:8080/subtasks/3"); + HttpRequest requestNew = HttpRequest + .newBuilder() + .uri(urlNew) + .POST(HttpRequest.BodyPublishers.ofString(subtask2UpdateJson)) + .build(); + + HttpResponse responseNew = httpClient.send(requestNew, HttpResponse.BodyHandlers.ofString()); + assertEquals(404, responseNew.statusCode(), "Неверный код ответа сервера"); + + LocalDateTime expectedStartTime2 = LocalDateTime.of(2025, 4, 28, 23, 7); + Duration expectedDuration2 = Duration.ofMinutes(180); + Subtask subtask3 = new Subtask(3, "Подзадача 2 эпика 1", "описание подзадачи 2 эпика 1", 1, expectedStartTime2, expectedDuration2); + taskManager.addSubtask(1, subtask3); + + LocalDateTime expectedStartTime2Update = LocalDateTime.of(2025, 4, 27, 23, 7); + Duration expectedDuration2Update = Duration.ofMinutes(300); + Subtask subtask3Update = new Subtask(3, "Подзадача 2 эпика 1", "описание подзадачи 2 эпика 1", 1, expectedStartTime2Update, expectedDuration2Update); + + String subtask3UpdateJson = gson.toJson(subtask3Update); + + HttpRequest requestNewTwo = HttpRequest + .newBuilder() + .uri(urlNew) + .POST(HttpRequest.BodyPublishers.ofString(subtask3UpdateJson)) + .build(); + + HttpResponse responseNewTwo = httpClient.send(requestNewTwo, HttpResponse.BodyHandlers.ofString()); + assertEquals(406, responseNewTwo.statusCode(), "Неверный код ответа сервера"); + } + + @Test + void testDeleteAllSubtusks() throws IOException, InterruptedException { + Epic epic1 = new Epic(1, "Заголовок эпика 1", "Подробное описание эпика 1", Status.NEW); + taskManager.addEpic(epic1); + + LocalDateTime expectedStartTime1 = LocalDateTime.of(2025, 4, 27, 23, 7); + Duration expectedDuration1 = Duration.ofMinutes(300); + Subtask subtask1 = new Subtask(2, "Подзадача 1 эпика 1", "описание подзадачи 1 эпика 1", 1, expectedStartTime1, expectedDuration1); + taskManager.addSubtask(1, subtask1); + + URI url = URI.create("http://localhost:8080/subtasks"); + HttpRequest request = HttpRequest + .newBuilder() + .uri(url) + .DELETE() + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode(), "Неверный код ответа сервера"); + assertTrue(taskManager.getAllSubtasks().isEmpty(), "Не все подзадачи удалены"); + } + + @Test + void testDeleteEpicById() throws IOException, InterruptedException { + Epic epic1 = new Epic(1, "Заголовок эпика 1", "Подробное описание эпика 1", Status.NEW); + taskManager.addEpic(epic1); + + LocalDateTime expectedStartTime1 = LocalDateTime.of(2025, 4, 27, 23, 7); + Duration expectedDuration1 = Duration.ofMinutes(300); + Subtask subtask1 = new Subtask(2, "Подзадача 1 эпика 1", "описание подзадачи 1 эпика 1", 1, expectedStartTime1, expectedDuration1); + taskManager.addSubtask(1, subtask1); + + URI url = URI.create("http://localhost:8080/subtasks/3"); + HttpRequest request = HttpRequest + .newBuilder() + .uri(url) + .DELETE() + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(404, response.statusCode(), "Неверный код ответа сервера"); + + URI urlNew = URI.create("http://localhost:8080/subtasks/2"); + HttpRequest requestNew = HttpRequest + .newBuilder() + .uri(urlNew) + .DELETE() + .build(); + + HttpResponse responseNew = httpClient.send(requestNew, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, responseNew.statusCode(), "Неверный код ответа сервера"); + assertTrue(taskManager.getAllSubtasks().isEmpty(), "Эпик 1 не удален"); + } + +} \ No newline at end of file diff --git a/test/HttpTaskServerTasksTest.java b/test/HttpTaskServerTasksTest.java new file mode 100644 index 0000000..687a5d1 --- /dev/null +++ b/test/HttpTaskServerTasksTest.java @@ -0,0 +1,244 @@ +import com.google.gson.Gson; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +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 java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +class HttpTaskServerTasksTest { + private static TaskManager taskManager; + private static HttpTaskServer httpTaskServer; + private static Gson gson; + private static HttpClient httpClient; + + @BeforeAll + static void beforeAll() throws IOException { + taskManager = Managers.getDefault(); + httpTaskServer = new HttpTaskServer(taskManager); + gson = httpTaskServer.getGson(); + httpTaskServer.start(); + httpClient = HttpClient.newHttpClient(); + } + + @AfterAll + static void afterAll() { + httpTaskServer.stop(); + httpClient.close(); + } + + @BeforeEach + void beforeEach() { + taskManager.deleteAllTask(); + taskManager.deleteAllEpic(); + taskManager.setNewId(1); + } + + @Test + void testReturnAllTasks() throws IOException, InterruptedException { + LocalDateTime expectedStartTime1 = LocalDateTime.of(2025, 4, 25, 23, 7); + Duration expectedDuration1 = Duration.ofMinutes(150); + Task task1 = new Task(1, "Задачи 1", "описание задачи 1", expectedStartTime1, expectedDuration1); + taskManager.addTask(task1); + + String task1Json = gson.toJson(task1); + + URI url = URI.create("http://localhost:8080/tasks"); + HttpRequest request = HttpRequest + .newBuilder() + .uri(url) + .GET() + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + String responseBody = response.body(); + + assertEquals(200, response.statusCode(), "Неверный код ответа сервера"); + assertTrue(responseBody.contains(task1Json), "Нет добавленной задачи в теле ответа сервера"); + + taskManager.deleteAllTask(); + + HttpResponse responseNew = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + String responseBodyNew = responseNew.body(); + + assertEquals(200, responseNew.statusCode(), "Неверный код ответа сервера после удаления всех задач"); + assertEquals("[]", responseBodyNew, "Тело ответа сервера не пустое после удаления всех задач"); + } + + @Test + void testReturnTaskById() throws IOException, InterruptedException { + LocalDateTime expectedStartTime1 = LocalDateTime.of(2025, 4, 25, 23, 7); + Duration expectedDuration1 = Duration.ofMinutes(150); + Task task1 = new Task(1, "Задачи 1", "описание задачи 1", expectedStartTime1, expectedDuration1); + taskManager.addTask(task1); + + String task1Json = gson.toJson(task1); + + URI url = URI.create("http://localhost:8080/tasks/1"); + HttpRequest request = HttpRequest + .newBuilder() + .uri(url) + .GET() + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + String responseBody = response.body(); + + assertEquals(200, response.statusCode(), "Неверный код ответа сервера"); + assertTrue(responseBody.contains(task1Json), "Нет добавленной задачи в теле ответа сервера"); + + taskManager.deleteAllTask(); + + HttpResponse responseNew = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + String responseBodyNew = responseNew.body(); + + assertEquals(404, responseNew.statusCode(), "Неверный код ответа сервера после удаления всех задач"); + assertEquals("Задача с идентификатором 1 не найдена", responseBodyNew, "Тело ответа сервера не пустое после удаления всех задач"); + } + + @Test + void testAddTask() throws IOException, InterruptedException { + LocalDateTime expectedStartTime1 = LocalDateTime.of(2025, 4, 25, 23, 7); + Duration expectedDuration1 = Duration.ofMinutes(150); + Task task1 = new Task(1, "Задача 1", "описание задачи 1", expectedStartTime1, expectedDuration1); + + String task1Json = gson.toJson(task1); + + URI url = URI.create("http://localhost:8080/tasks"); + HttpRequest request = HttpRequest + .newBuilder() + .uri(url) + .POST(HttpRequest.BodyPublishers.ofString(task1Json)) + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(201, response.statusCode(), "Неверный код ответа сервера"); + + List tasksFromManager = taskManager.getAllTasks(); + + assertNotNull(tasksFromManager, "Задачи не возвращаются"); + assertEquals(1, tasksFromManager.size(), "Некорректное количество задач"); + assertEquals("Задача 1", tasksFromManager.getFirst().getTitle(), "Некорректное имя задачи"); + } + + @Test + void testUpdateTaskById() throws IOException, InterruptedException { + LocalDateTime expectedStartTime1 = LocalDateTime.of(2025, 4, 25, 23, 7); + Duration expectedDuration1 = Duration.ofMinutes(150); + Task task1 = new Task(1, "Задача 1", "описание задачи 1", expectedStartTime1, expectedDuration1); + taskManager.addTask(task1); + + Task task1Update = new Task(1, "Задача 1 изменена", "описание задачи 1 изменено", expectedStartTime1, expectedDuration1); + + String task1UpdateJson = gson.toJson(task1Update); + + URI url = URI.create("http://localhost:8080/tasks/1"); + HttpRequest request = HttpRequest + .newBuilder() + .uri(url) + .POST(HttpRequest.BodyPublishers.ofString(task1UpdateJson)) + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(201, response.statusCode(), "Неверный код ответа сервера"); + + List tasksFromManager = taskManager.getAllTasks(); + + assertNotNull(tasksFromManager, "Задачи не возвращаются"); + assertEquals(1, tasksFromManager.size(), "Некорректное количество задач"); + assertEquals("Задача 1 изменена", tasksFromManager.getFirst().getTitle(), "Имя задачи не обновилось"); + assertEquals("описание задачи 1 изменено", tasksFromManager.getFirst().getDescription(), "Описание задачи не обновилось"); + + Task task2Update = new Task(2, "Задача 1 изменена", "описание задачи 1 изменено", expectedStartTime1, expectedDuration1); + + String task2UpdateJson = gson.toJson(task2Update); + + URI urlNew = URI.create("http://localhost:8080/tasks/2"); + HttpRequest requestNew = HttpRequest + .newBuilder() + .uri(urlNew) + .POST(HttpRequest.BodyPublishers.ofString(task2UpdateJson)) + .build(); + + HttpResponse responseNew = httpClient.send(requestNew, HttpResponse.BodyHandlers.ofString()); + assertEquals(404, responseNew.statusCode(), "Неверный код ответа сервера"); + + LocalDateTime expectedStartTime2 = LocalDateTime.of(2025, 4, 26, 23, 7); + Duration expectedDuration2 = Duration.ofMinutes(150); + Task task2 = new Task(2, "Задача 2", "описание задачи 2", expectedStartTime2, expectedDuration2); + taskManager.addTask(task2); + + LocalDateTime expectedStartTime2Update = LocalDateTime.of(2025, 4, 25, 23, 7); + Duration expectedDuration2Update = Duration.ofMinutes(180); + Task task3Update = new Task(2, "Задача 2 изменена", "описание задачи 2 изменено", expectedStartTime2Update, expectedDuration2Update); + + String task3UpdateJson = gson.toJson(task3Update); + + HttpRequest requestNewTwo = HttpRequest + .newBuilder() + .uri(urlNew) + .POST(HttpRequest.BodyPublishers.ofString(task3UpdateJson)) + .build(); + + HttpResponse responseNewTwo = httpClient.send(requestNewTwo, HttpResponse.BodyHandlers.ofString()); + assertEquals(406, responseNewTwo.statusCode(), "Неверный код ответа сервера"); + } + + @Test + void testDeleteAllTasks() throws IOException, InterruptedException { + LocalDateTime expectedStartTime1 = LocalDateTime.of(2025, 4, 25, 23, 7); + Duration expectedDuration1 = Duration.ofMinutes(150); + Task task1 = new Task(1, "Задача 1", "описание задачи 1", expectedStartTime1, expectedDuration1); + taskManager.addTask(task1); + + URI url = URI.create("http://localhost:8080/tasks"); + HttpRequest request = HttpRequest + .newBuilder() + .uri(url) + .DELETE() + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode(), "Неверный код ответа сервера"); + assertTrue(taskManager.getAllTasks().isEmpty(), "Не все задачи удалены"); + } + + @Test + void testDeleteTaskById() throws IOException, InterruptedException { + LocalDateTime expectedStartTime1 = LocalDateTime.of(2025, 4, 25, 23, 7); + Duration expectedDuration1 = Duration.ofMinutes(150); + Task task1 = new Task(1, "Задача 1", "описание задачи 1", expectedStartTime1, expectedDuration1); + taskManager.addTask(task1); + + URI url = URI.create("http://localhost:8080/tasks/2"); + HttpRequest request = HttpRequest + .newBuilder() + .uri(url) + .DELETE() + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(404, response.statusCode(), "Неверный код ответа сервера"); + + URI urlNew = URI.create("http://localhost:8080/tasks/1"); + HttpRequest requestNew = HttpRequest + .newBuilder() + .uri(urlNew) + .DELETE() + .build(); + + HttpResponse responseNew = httpClient.send(requestNew, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, responseNew.statusCode(), "Неверный код ответа сервера"); + assertTrue(taskManager.getAllTasks().isEmpty(), "Задача 1 не удалена"); + } + +} \ No newline at end of file diff --git a/test/TaskManagerTest.java b/test/TaskManagerTest.java index 3f5488d..c6b2c6b 100644 --- a/test/TaskManagerTest.java +++ b/test/TaskManagerTest.java @@ -264,7 +264,7 @@ void allTypesTasksHaveCorrectTimeParameters() { assertEquals(expectedEndTime4, taskManagerTime.getEpicByID(2).getEndTime(), "После обновления подзадачи у эпика неверное время окончания"); Subtask subtask5 = new Subtask("Подзадача 3 эпика 1", "описание подзадачи 3 эпика 1", 2); - taskManagerTime.updateSubtaskByID(subtask5); + taskManagerTime.addSubtask(2, subtask5); assertEquals(expectedStartTime4, taskManagerTime.getEpicByID(2).getStartTime(), "После добавления подзадачи без времени у эпика неверное время начала"); assertEquals(expectedDuration4, taskManagerTime.getEpicByID(2).getDuration(), "После добавления подзадачи без времени у эпика неверная продолжительность"); @@ -297,7 +297,10 @@ void getPriorityTasksAndCheckSortingAndAddingIntersection() { Subtask subtask1 = new Subtask("Подзадача 1 эпика 1", "описание подзадачи 1 эпика 1", 2, expectedStartTime2, expectedDuration2); taskManagerTime.addSubtask(2, subtask1); Subtask subtask2 = new Subtask("Подзадача 2 эпика 1", "описание подзадачи 2 эпика 1", 2, expectedStartTime3, expectedDuration3); - taskManagerTime.addSubtask(2, subtask2); + assertThrows( + TaskOverlapsException.class, + () -> taskManagerTime.addSubtask(2, subtask2), "Подзадача пересекается по времени" + ); Subtask subtask3 = new Subtask("Подзадача 3 эпика 1", "описание подзадачи 3 эпика 1", 2, expectedStartTime4, expectedDuration4); taskManagerTime.addSubtask(2, subtask3);