diff --git a/.idea/dictionaries/Andrey.xml b/.idea/dictionaries/Andrey.xml
new file mode 100644
index 0000000..59fb6f7
--- /dev/null
+++ b/.idea/dictionaries/Andrey.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/gson_2_9_0.xml b/.idea/libraries/gson_2_9_0.xml
new file mode 100644
index 0000000..2377008
--- /dev/null
+++ b/.idea/libraries/gson_2_9_0.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml
new file mode 100644
index 0000000..2b63946
--- /dev/null
+++ b/.idea/uiDesigner.xml
@@ -0,0 +1,124 @@
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index ec0749b..8620317 100644
--- a/README.md
+++ b/README.md
@@ -11,4 +11,7 @@
Сохранение списка задач в файл. Восстановление задач из файла.
## Спринт №8
-Добавляем дату и время
\ No newline at end of file
+Добавляем дату и время
+
+## Спринт №9
+Реализуем HTTP API
\ No newline at end of file
diff --git a/data/tasks.csv b/data/tasks.csv
index 738a868..346a5e3 100644
--- a/data/tasks.csv
+++ b/data/tasks.csv
@@ -1,6 +1,6 @@
id;DateTime;Duration(min);type;name;status;description;epic
-0;2024.12.31 12:05;15;TASK;Задача №1;DONE;Описание задачи №1;
-1;2024.12.31 23:55;10;TASK;Задача №2;NEW;С новым годом!;
+1;2024.12.31 12:05;15;TASK;Задача №1;DONE;Описание задачи №1;
+8;2024.12.31 23:55;10;TASK;Задача №...;NEW;С новым годом!;
2;2024.12.31 10:55;110;EPIC;Эпик №1;IN_PROGRESS;-;
6;2024.12.31 14:45;10;EPIC;Эпик №2;NEW;-;
3;2024.12.31 12:30;15;SUBTASK;Подзадача №1;DONE;-;2
diff --git a/java-kanban.iml b/java-kanban.iml
index d6e13ce..08cac80 100644
--- a/java-kanban.iml
+++ b/java-kanban.iml
@@ -25,5 +25,6 @@
+
\ No newline at end of file
diff --git a/src/Main.java b/src/Main.java
index f411f87..d18283d 100644
--- a/src/Main.java
+++ b/src/Main.java
@@ -1,6 +1,9 @@
+import managers.Managers;
+import managers.TaskManager;
import tasks.Epic;
import tasks.Subtask;
import tasks.Task;
+import managers.FileBackedTaskManager;
import java.time.Duration;
import java.time.LocalDateTime;
@@ -18,7 +21,7 @@ public static void main(String[] args) {
System.out.println("\nПроверяем статус эпика : " + manager.getEpic(6).toString());
- System.out.println("\nПроверяем статус задачи : " + manager.getTask(0).toString());
+ System.out.println("\nПроверяем статус задачи : " + manager.getTask(1).toString());
System.out.println("\nПроверяем статус подзадачи : " + manager.getSubtask(5).toString());
diff --git a/src/adapters/DurationAdapter.java b/src/adapters/DurationAdapter.java
new file mode 100644
index 0000000..0812e5d
--- /dev/null
+++ b/src/adapters/DurationAdapter.java
@@ -0,0 +1,25 @@
+package adapters;
+
+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(final JsonWriter jsonWriter, final Duration duration) throws IOException {
+ if (duration == null) {
+ jsonWriter.value(0);
+ return;
+ }
+ jsonWriter.value(duration.toMinutes());
+ }
+
+ @Override
+ public Duration read(final JsonReader jsonReader) throws IOException {
+ return Duration.ofMinutes(Integer.decode(jsonReader.nextString()));
+ }
+
+}
diff --git a/src/adapters/JsFormatter.java b/src/adapters/JsFormatter.java
new file mode 100644
index 0000000..4ecde31
--- /dev/null
+++ b/src/adapters/JsFormatter.java
@@ -0,0 +1,11 @@
+package adapters;
+
+public class JsFormatter {
+ public static final String MESSAGE = "{\n \"message\":\"%s\"\n}";
+
+ public static final String ID_MESSAGE = "{\n \"id\":%d,"
+ + "\n \"message\":\"%s\"\n}";
+
+ private JsFormatter() {
+ }
+}
diff --git a/src/adapters/LocalDateTimeAdapter.java b/src/adapters/LocalDateTimeAdapter.java
new file mode 100644
index 0000000..84ef5b9
--- /dev/null
+++ b/src/adapters/LocalDateTimeAdapter.java
@@ -0,0 +1,32 @@
+package adapters;
+
+import com.google.gson.TypeAdapter;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
+import tasks.Task;
+
+import java.io.IOException;
+import java.time.LocalDateTime;
+
+
+public class LocalDateTimeAdapter extends TypeAdapter {
+
+ @Override
+ public void write(final JsonWriter jsonWriter, final LocalDateTime localDateTime) throws IOException {
+ if (localDateTime == null) {
+ jsonWriter.value("null");
+ return;
+ }
+ jsonWriter.value(localDateTime.format(Task.DATE_TIME_FORMATTER));
+ }
+
+ @Override
+ public LocalDateTime read(final JsonReader jsonReader) throws IOException {
+ String value = jsonReader.nextString();
+ if (value.equals("null")) {
+ return null;
+ }
+ return LocalDateTime.parse(value, Task.DATE_TIME_FORMATTER);
+ }
+
+}
diff --git a/src/adapters/TaskStatusAdapter.java b/src/adapters/TaskStatusAdapter.java
new file mode 100644
index 0000000..fea94f3
--- /dev/null
+++ b/src/adapters/TaskStatusAdapter.java
@@ -0,0 +1,29 @@
+package adapters;
+
+import com.google.gson.TypeAdapter;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
+import tasks.TaskStatus;
+
+import java.io.IOException;
+
+public class TaskStatusAdapter extends TypeAdapter {
+ @Override
+ public void write(final JsonWriter jsonWriter, final TaskStatus taskStatus) throws IOException {
+ if (taskStatus == null) {
+ jsonWriter.value(TaskStatus.NEW.toString());
+ return;
+ }
+ jsonWriter.value(taskStatus.toString());
+ }
+
+ @Override
+ public TaskStatus read(final JsonReader jsonReader) throws IOException {
+ TaskStatus taskStatus = TaskStatus.valueOf(jsonReader.nextString());
+ if (taskStatus == null) {
+ return TaskStatus.NEW;
+ }
+ return taskStatus;
+ }
+
+}
diff --git a/src/exceptions/NotFoundException.java b/src/exceptions/NotFoundException.java
new file mode 100644
index 0000000..ee3806e
--- /dev/null
+++ b/src/exceptions/NotFoundException.java
@@ -0,0 +1,15 @@
+package exceptions;
+
+public class NotFoundException extends RuntimeException {
+ private final String taskInfo;
+
+ public NotFoundException(final String text, final String taskInfo) {
+ super(text);
+ this.taskInfo = taskInfo;
+ }
+
+ public String getDetailMessage() {
+ return getMessage() + " " + taskInfo;
+ }
+
+}
diff --git a/src/exceptions/TaskCrossTimeException.java b/src/exceptions/TimeIntersectionException.java
similarity index 60%
rename from src/exceptions/TaskCrossTimeException.java
rename to src/exceptions/TimeIntersectionException.java
index 22f7912..e977c87 100644
--- a/src/exceptions/TaskCrossTimeException.java
+++ b/src/exceptions/TimeIntersectionException.java
@@ -1,9 +1,9 @@
package exceptions;
-public class TaskCrossTimeException extends RuntimeException {
+public class TimeIntersectionException extends RuntimeException {
private final String existsTasks;
- public TaskCrossTimeException(final String text, final String existsTasks) {
+ public TimeIntersectionException(final String text, final String existsTasks) {
super(text);
this.existsTasks = existsTasks;
}
diff --git a/src/httpapi/BaseHttpHandler.java b/src/httpapi/BaseHttpHandler.java
new file mode 100644
index 0000000..42300c6
--- /dev/null
+++ b/src/httpapi/BaseHttpHandler.java
@@ -0,0 +1,60 @@
+package httpapi;
+
+import adapters.JsFormatter;
+import com.sun.net.httpserver.HttpExchange;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Optional;
+
+public class BaseHttpHandler {
+ protected static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
+
+ /**
+ * Передач ответа на HTTP запрос
+ *
+ * @param h- объект http запроса
+ * @param text - текст ответа
+ * @param retCode - код завершения обработки запроса
+ */
+ public void sendText(HttpExchange h, String text, int retCode) /*throws IOException*/ {
+ try {
+ byte[] resp = text.getBytes(StandardCharsets.UTF_8);
+ h.getResponseHeaders().add("Content-Type", "application/json;charset=utf-8");
+ h.sendResponseHeaders(retCode, resp.length);
+ h.getResponseBody().write(resp);
+ } catch (IOException e) {
+ System.out.println("Произошла ошибка при передаче ответа на запрос.\n" +
+ e.getMessage());
+ }
+ }
+
+ /**
+ * Чтение параметра http запроса
+ *
+ * @param h - объект http запроса
+ * @return - идентификатор элемента в списке задач
+ */
+ public Optional getElementId(HttpExchange h) {
+ String[] pathParts = h.getRequestURI().getPath().split("/");
+ if (pathParts.length < 3) {
+ return Optional.empty();
+ }
+ try {
+ return Optional.of(Integer.parseInt(pathParts[2]));
+ } catch (NumberFormatException exception) {
+ return Optional.empty();
+ }
+ }
+
+ /**
+ * Обработка Нераспознанного запроса
+ */
+ protected void handleUnknown(HttpExchange exchange, String method) {
+ sendText(exchange,
+ String.format(JsFormatter.MESSAGE, "Метод не поддержмвается - " + method),
+ 406);
+ }
+
+}
\ No newline at end of file
diff --git a/src/httpapi/HttpEpicsHandler.java b/src/httpapi/HttpEpicsHandler.java
new file mode 100644
index 0000000..20f2738
--- /dev/null
+++ b/src/httpapi/HttpEpicsHandler.java
@@ -0,0 +1,107 @@
+package httpapi;
+
+import adapters.JsFormatter;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import exceptions.NotFoundException;
+import exceptions.TimeIntersectionException;
+import managers.TaskManager;
+import tasks.Epic;
+import tasks.Subtask;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * класс обработки http запросов по контексту /epics
+ */
+public class HttpEpicsHandler extends BaseHttpHandler implements HttpHandler {
+ private final TaskManager manager;
+
+ public HttpEpicsHandler(TaskManager manager) {
+ this.manager = manager;
+ }
+
+ @Override
+ public void handle(HttpExchange exchange) throws IOException {
+ String method = exchange.getRequestMethod();
+ String endpointName = method + exchange.getRequestURI().getPath();
+
+ try {
+ Optional epicIdOpt = getElementId(exchange);
+ if (method.equals("GET")) {
+ if (epicIdOpt.isEmpty()) {
+ List epics = manager.getEpicList();
+ sendText(exchange, HttpTaskServer.gson.toJson(epics), 200);
+ } else {
+ int epicId = epicIdOpt.get();
+ Epic epic = manager.getEpic(epicId);
+
+ String path = exchange.getRequestURI().getPath();
+ if (!path.contains("subtasks")) {
+ sendText(exchange, HttpTaskServer.gson.toJson(epic), 200);
+ } else {
+ List subtasks = manager.getSubtasksByEpic(epicId);
+ sendText(exchange, HttpTaskServer.gson.toJson(subtasks), 200);
+ }
+ }
+ } else if (method.equals("POST")) {
+ // читаем описание эпика переданной в запросе
+ InputStream bodyInputStream = exchange.getRequestBody();
+ String body = new String(bodyInputStream.readAllBytes(), BaseHttpHandler.DEFAULT_CHARSET);
+ Epic newEpic = HttpTaskServer.gson.fromJson(body, Epic.class);
+
+ if (epicIdOpt.isEmpty()) {
+ // Добавление нового эпика если не указан идентификатор
+ int id = manager.addNewEpic(newEpic);
+ if (id > 0) {
+ sendText(exchange,
+ String.format(JsFormatter.ID_MESSAGE, id, "Эпик успешно добавлена."),
+ 201);
+ } else {
+ throw new Exception(endpointName +
+ " Ошибка при добавлении эпика. retCode=" + id);
+ }
+ } else {
+ // Обновление эпика по идентификатору
+ int updateId = epicIdOpt.get();
+ newEpic.setId(updateId); // на всякий случай устанавлмваем id из параметра
+ manager.updateEpic(newEpic);
+ sendText(exchange,
+ String.format(JsFormatter.ID_MESSAGE, updateId, "Задача успешно обновлена."),
+ 201);
+ }
+ } else if (method.equals("DELETE")) {
+ // Удаление задачи
+ if (epicIdOpt.isEmpty()) {
+ sendText(exchange,
+ String.format(JsFormatter.MESSAGE, "Идентификатор эпика не указан."),
+ 406);
+ } else {
+ int epicId = epicIdOpt.get();
+ manager.removeEpic(epicId);
+ sendText(exchange,
+ String.format(JsFormatter.ID_MESSAGE, epicId, "эпик успешно удален."),
+ 200);
+ }
+ } else {
+ handleUnknown(exchange, endpointName);
+ }
+ } catch (NotFoundException e) { // Данные не найдены
+ sendText(exchange,
+ String.format(JsFormatter.MESSAGE, e.getDetailMessage()),
+ 404);
+ } catch (TimeIntersectionException e) { // Пересечение времени выполнения задач
+ sendText(exchange,
+ String.format(JsFormatter.MESSAGE, e.getDetailMessage()),
+ 406);
+ } catch (Exception e) { // Прочие ошибки
+ sendText(exchange,
+ String.format(JsFormatter.MESSAGE, endpointName + "Ошибка программы.\n" + e.getMessage()),
+ 500);
+ }
+ }
+
+}
diff --git a/src/httpapi/HttpHistoryHandler.java b/src/httpapi/HttpHistoryHandler.java
new file mode 100644
index 0000000..04e3853
--- /dev/null
+++ b/src/httpapi/HttpHistoryHandler.java
@@ -0,0 +1,44 @@
+package httpapi;
+
+import adapters.JsFormatter;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import exceptions.NotFoundException;
+import managers.TaskManager;
+import tasks.Task;
+
+import java.io.IOException;
+import java.util.List;
+
+public class HttpHistoryHandler extends BaseHttpHandler implements HttpHandler {
+ private final TaskManager manager;
+
+ public HttpHistoryHandler(TaskManager manager) {
+ this.manager = manager;
+ }
+
+ @Override
+ public void handle(HttpExchange exchange) throws IOException {
+ String method = exchange.getRequestMethod();
+ String endpointName = method + exchange.getRequestURI().getPath();
+
+ try {
+ if (!method.equals("GET")) {
+ handleUnknown(exchange, endpointName);
+ return;
+ }
+
+ List history = manager.getHistory();
+ sendText(exchange, HttpTaskServer.gson.toJson(history), 200);
+
+ } catch (NotFoundException e) { // Данные не найдены
+ sendText(exchange,
+ String.format(JsFormatter.MESSAGE, e.getDetailMessage()),
+ 404);
+ } catch (Exception e) { // Прочие ошибки
+ String.format(JsFormatter.MESSAGE, endpointName +
+ "Ошибка программы.\n" + e.getMessage(),
+ 500);
+ }
+ }
+}
diff --git a/src/httpapi/HttpPrioritizedHandler.java b/src/httpapi/HttpPrioritizedHandler.java
new file mode 100644
index 0000000..b8465b8
--- /dev/null
+++ b/src/httpapi/HttpPrioritizedHandler.java
@@ -0,0 +1,46 @@
+package httpapi;
+
+import adapters.JsFormatter;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import exceptions.NotFoundException;
+import managers.TaskManager;
+import tasks.Task;
+
+import java.io.IOException;
+import java.util.List;
+
+public class HttpPrioritizedHandler extends BaseHttpHandler implements HttpHandler {
+ private final TaskManager manager;
+
+ public HttpPrioritizedHandler(TaskManager manager) {
+ this.manager = manager;
+ }
+
+ @Override
+ public void handle(HttpExchange exchange) throws IOException {
+ String method = exchange.getRequestMethod();
+ String endpointName = method + exchange.getRequestURI().getPath();
+ try {
+ if (!method.equals("GET")) {
+ handleUnknown(exchange, endpointName);
+ return;
+ }
+
+ List prioritizedTasks = manager.getPrioritizedTasks();
+ sendText(exchange, HttpTaskServer.gson.toJson(prioritizedTasks),
+ 200);
+
+ } catch (NotFoundException e) { // Данные не найдены
+ sendText(exchange,
+ String.format(JsFormatter.MESSAGE, e.getDetailMessage()),
+ 404);
+ } catch (Exception e) { // Прочие ошибки
+ sendText(exchange,
+ String.format(JsFormatter.MESSAGE, endpointName +
+ "Ошибка программы.\n" + e.getMessage()),
+ 500);
+ }
+ }
+
+}
diff --git a/src/httpapi/HttpSubtasksHandler.java b/src/httpapi/HttpSubtasksHandler.java
new file mode 100644
index 0000000..dea4027
--- /dev/null
+++ b/src/httpapi/HttpSubtasksHandler.java
@@ -0,0 +1,96 @@
+package httpapi;
+
+import adapters.JsFormatter;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import exceptions.NotFoundException;
+import exceptions.TimeIntersectionException;
+import managers.TaskManager;
+import tasks.Subtask;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Optional;
+
+public class HttpSubtasksHandler extends BaseHttpHandler implements HttpHandler {
+
+ private final TaskManager manager;
+
+ public HttpSubtasksHandler(TaskManager manager) {
+ this.manager = manager;
+ }
+
+ @Override
+ public void handle(HttpExchange exchange) throws IOException {
+ String method = exchange.getRequestMethod();
+ String endpointName = method + exchange.getRequestURI().getPath();
+
+ try {
+ Optional subtaskIdOpt = getElementId(exchange);
+ if (method.equals("GET")) {
+ if (subtaskIdOpt.isEmpty()) {
+ List subtasks = manager.getSubtaskList();
+ sendText(exchange, HttpTaskServer.gson.toJson(subtasks), 200);
+ } else {
+ Subtask subtask = manager.getSubtask(subtaskIdOpt.get());
+ sendText(exchange, HttpTaskServer.gson.toJson(subtask), 200);
+ }
+ } else if (method.equals("POST")) {
+ // читаем описание подзадачи переданной в запросе
+ InputStream bodyInputStream = exchange.getRequestBody();
+ String body = new String(bodyInputStream.readAllBytes(), BaseHttpHandler.DEFAULT_CHARSET);
+ Subtask newSubtask = HttpTaskServer.gson.fromJson(body, Subtask.class);
+
+ if (subtaskIdOpt.isEmpty()) {
+ // Добавление новой подзадачи если не указан идентификатор
+ int id = manager.addNewSubtask(newSubtask);
+ if (id > 0) {
+ sendText(exchange,
+ String.format(JsFormatter.ID_MESSAGE, id, "Подзадача успешно добавлена."),
+ 201);
+ } else {
+ throw new Exception(endpointName +
+ " Ошибка при добавлении подзадачи. retCode=" + id);
+ }
+ } else {
+ // Обновление подзадачи по идентификатору
+ int updateId = subtaskIdOpt.get();
+ newSubtask.setId(updateId); // на всякий случай устанавлмваем id из параметра запроса
+ manager.updateSubtask(newSubtask);
+ sendText(exchange,
+ String.format(JsFormatter.ID_MESSAGE, updateId, "Подзадача успешно обновлена."),
+ 201);
+ }
+ } else if (method.equals("DELETE")) {
+ // Удаление подзадачи
+ if (subtaskIdOpt.isEmpty()) {
+ sendText(exchange,
+ String.format(JsFormatter.MESSAGE, "Идентификатор подзадачи не указан."),
+ 406);
+ } else {
+ int subtaskId = subtaskIdOpt.get();
+ manager.removeSubtask(subtaskId);
+ sendText(exchange,
+ String.format(JsFormatter.ID_MESSAGE, subtaskId, "Задача успешно удалена."),
+ 200);
+ }
+ } else {
+ handleUnknown(exchange, endpointName);
+ }
+ } catch (NotFoundException e) { // Данные не найдены
+ sendText(exchange,
+ String.format(JsFormatter.MESSAGE, e.getDetailMessage()),
+ 404);
+ } catch (TimeIntersectionException e) { // Пересечение времени выполнения задач
+ sendText(exchange,
+ String.format(JsFormatter.MESSAGE, e.getDetailMessage()),
+ 406);
+ } catch (Exception e) { // Прочие ошибки
+ sendText(exchange,
+ String.format(JsFormatter.MESSAGE, endpointName + "Ошибка программы.\n" + e.getMessage()),
+ 500);
+ }
+ }
+
+}
diff --git a/src/httpapi/HttpTaskServer.java b/src/httpapi/HttpTaskServer.java
new file mode 100644
index 0000000..243659b
--- /dev/null
+++ b/src/httpapi/HttpTaskServer.java
@@ -0,0 +1,53 @@
+package httpapi;
+
+import adapters.DurationAdapter;
+import adapters.LocalDateTimeAdapter;
+import adapters.TaskStatusAdapter;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.sun.net.httpserver.HttpServer;
+import managers.Managers;
+import managers.TaskManager;
+import tasks.TaskStatus;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.time.Duration;
+import java.time.LocalDateTime;
+
+public class HttpTaskServer {
+ private static final int PORT = 8080;
+ private static HttpServer httpServer;
+ private static TaskManager manager = Managers.getDefault();
+
+ public static Gson gson = new GsonBuilder()
+ .setPrettyPrinting()
+ .registerTypeAdapter(LocalDateTime.class, new LocalDateTimeAdapter())
+ .registerTypeAdapter(Duration.class, new DurationAdapter())
+ .registerTypeAdapter(TaskStatus.class, new TaskStatusAdapter())
+ .create();
+
+ public HttpTaskServer(TaskManager manager) {
+ this.manager = manager;
+ }
+
+ public static void start() throws IOException {
+ httpServer = HttpServer.create(new InetSocketAddress(PORT), 0);
+ httpServer.createContext("/tasks", new HttpTasksHandler(manager));
+ httpServer.createContext("/subtasks", new HttpSubtasksHandler(manager));
+ httpServer.createContext("/epics", new HttpEpicsHandler(manager));
+ httpServer.createContext("/history", new HttpHistoryHandler(manager));
+ httpServer.createContext("/prioritized", new HttpPrioritizedHandler(manager));
+ httpServer.start();
+ }
+
+ public static void stop() {
+ httpServer.stop(0);
+ }
+
+ public static void main(String[] args) throws IOException, InterruptedException {
+
+ start();
+ System.out.println("HTTP-сервер запущен на " + PORT + " порту!");
+ }
+}
diff --git a/src/httpapi/HttpTasksHandler.java b/src/httpapi/HttpTasksHandler.java
new file mode 100644
index 0000000..e4e53d9
--- /dev/null
+++ b/src/httpapi/HttpTasksHandler.java
@@ -0,0 +1,97 @@
+package httpapi;
+
+import adapters.JsFormatter;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import exceptions.NotFoundException;
+import exceptions.TimeIntersectionException;
+import managers.TaskManager;
+import tasks.Task;
+
+import java.io.InputStream;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * класс обработки http запросов по контексту /tasks
+ */
+public class HttpTasksHandler extends BaseHttpHandler implements HttpHandler {
+
+ private final TaskManager manager;
+
+ public HttpTasksHandler(TaskManager manager) {
+ this.manager = manager;
+ }
+
+ @Override
+ public void handle(HttpExchange exchange) {
+ String method = exchange.getRequestMethod();
+ String endpointName = method + exchange.getRequestURI().getPath();
+
+ try {
+ Optional taskIdOpt = getElementId(exchange);
+ if (method.equals("GET")) {
+ if (taskIdOpt.isEmpty()) {
+ List tasks = manager.getTaskList();
+ sendText(exchange, HttpTaskServer.gson.toJson(tasks), 200);
+ } else {
+ Task task = manager.getTask(taskIdOpt.get());
+ sendText(exchange, HttpTaskServer.gson.toJson(task), 200);
+ }
+ } else if (method.equals("POST")) {
+ // читаем описание задачи переданной в запросе
+ InputStream bodyInputStream = exchange.getRequestBody();
+ String body = new String(bodyInputStream.readAllBytes(), BaseHttpHandler.DEFAULT_CHARSET);
+ Task newTask = HttpTaskServer.gson.fromJson(body, Task.class);
+
+ if (taskIdOpt.isEmpty()) {
+ // Добавление новой задачи если не указан идентификатор
+ int id = manager.addNewTask(newTask);
+ if (id > 0) {
+ sendText(exchange,
+ String.format(JsFormatter.ID_MESSAGE, id, "Задача успешно добавлена."),
+ 201);
+ } else {
+ throw new Exception(endpointName +
+ " Ошибка при добавлении задачи. retCode=" + id);
+ }
+ } else {
+ // Обновление задачи по идентификатору
+ int updateId = taskIdOpt.get();
+ newTask.setId(updateId); // на всякий случай устанавлмваем id из параметра
+ manager.updateTask(newTask);
+ sendText(exchange,
+ String.format(JsFormatter.ID_MESSAGE, updateId, "Задача успешно обновлена."),
+ 201);
+ }
+ } else if (method.equals("DELETE")) {
+ // Удаление задачи
+ if (taskIdOpt.isEmpty()) {
+ sendText(exchange,
+ String.format(JsFormatter.MESSAGE, "Идентификатор задачи не указан."),
+ 406);
+ } else {
+ int taskId = taskIdOpt.get();
+ manager.removeTask(taskId);
+ sendText(exchange,
+ String.format(JsFormatter.ID_MESSAGE, taskId, "Задача успешно удалена."),
+ 200);
+ }
+ } else {
+ handleUnknown(exchange, endpointName);
+ }
+ } catch (NotFoundException e) { // Данные не найдены
+ sendText(exchange,
+ String.format(JsFormatter.MESSAGE, e.getDetailMessage()),
+ 404);
+ } catch (TimeIntersectionException e) { // Пересечение времени выполнения задач
+ sendText(exchange,
+ String.format(JsFormatter.MESSAGE, e.getDetailMessage()),
+ 406);
+ } catch (Exception e) { // Прочие ошибки
+ sendText(exchange,
+ String.format(JsFormatter.MESSAGE, endpointName + "Ошибка программы.\n" + e.getMessage()),
+ 500);
+ }
+ }
+}
diff --git a/src/FileBackedTaskManager.java b/src/managers/FileBackedTaskManager.java
similarity index 90%
rename from src/FileBackedTaskManager.java
rename to src/managers/FileBackedTaskManager.java
index 9a1d153..1d4d902 100644
--- a/src/FileBackedTaskManager.java
+++ b/src/managers/FileBackedTaskManager.java
@@ -1,3 +1,5 @@
+package managers;
+
import exceptions.LoadException;
import exceptions.SaveException;
import tasks.*;
@@ -12,7 +14,7 @@
*/
public class FileBackedTaskManager extends InMemoryTaskManager {
private String fileName;
- private boolean loadInprogres;
+ private boolean loadInprogres = false;
/**
* Конструктор
@@ -84,26 +86,30 @@ public void save() throws SaveException {
fileWriter.write("id;DateTime;Duration(min);type;name;status;description;epic\n");
// сохраняем задачи
- String taskType = TaskType.TASK.toString();
- for (Task task : getTaskList()) {
- fileWriter.write(toString(task).replaceFirst("#type#", taskType)
- + "\n");
+ if (!taskList.isEmpty()) {
+ String taskType = TaskType.TASK.toString();
+ for (Task task : taskList.values()) {
+ fileWriter.write(toString(task).replaceFirst("#type#", taskType)
+ + "\n");
+ }
}
// сохраняем эпики
- taskType = TaskType.EPIC.toString();
- for (Epic epic : getEpicList()) {
- fileWriter.write(toString(epic).replaceFirst("#type#", taskType)
- + "\n");
+ if (!epicList.isEmpty()) {
+ String taskType = TaskType.EPIC.toString();
+ for (Epic epic : epicList.values()) {
+ fileWriter.write(toString(epic).replaceFirst("#type#", taskType)
+ + "\n");
+ }
}
-
// сохраняем подзадачи
- taskType = TaskType.SUBTASK.toString();
- for (Subtask subtask : getSubtaskList()) {
- fileWriter.write(toString(subtask).replaceFirst("#type#", taskType)
- + subtask.getEpicId() + "\n");
+ if (!subtaskList.isEmpty()) {
+ String taskType = TaskType.SUBTASK.toString();
+ for (Subtask subtask : subtaskList.values()) {
+ fileWriter.write(toString(subtask).replaceFirst("#type#", taskType)
+ + subtask.getEpicId() + "\n");
+ }
}
-
fileWriter.flush();
} catch (IOException e) {
@@ -118,7 +124,7 @@ public void save() throws SaveException {
* @param file - файл с описанием задач
* @return - ссылка на объект менеджера задач
*/
- static FileBackedTaskManager loadFromFile(File file) throws LoadException {
+ public static FileBackedTaskManager loadFromFile(File file) throws LoadException {
FileBackedTaskManager manager;
manager = new FileBackedTaskManager(file.getAbsolutePath());
diff --git a/src/HistoryManager.java b/src/managers/HistoryManager.java
similarity index 90%
rename from src/HistoryManager.java
rename to src/managers/HistoryManager.java
index b5fb84e..95d9099 100644
--- a/src/HistoryManager.java
+++ b/src/managers/HistoryManager.java
@@ -1,3 +1,5 @@
+package managers;
+
import tasks.Task;
import java.util.List;
diff --git a/src/InMemoryHistoryManager.java b/src/managers/InMemoryHistoryManager.java
similarity index 99%
rename from src/InMemoryHistoryManager.java
rename to src/managers/InMemoryHistoryManager.java
index 264e6b8..8d87494 100644
--- a/src/InMemoryHistoryManager.java
+++ b/src/managers/InMemoryHistoryManager.java
@@ -1,3 +1,5 @@
+package managers;
+
import tasks.Task;
import util.Node;
import util.SimpleLinkedList;
diff --git a/src/InMemoryTaskManager.java b/src/managers/InMemoryTaskManager.java
similarity index 63%
rename from src/InMemoryTaskManager.java
rename to src/managers/InMemoryTaskManager.java
index e70afc3..d1b17e4 100644
--- a/src/InMemoryTaskManager.java
+++ b/src/managers/InMemoryTaskManager.java
@@ -1,4 +1,7 @@
-import exceptions.TaskCrossTimeException;
+package managers;
+
+import exceptions.NotFoundException;
+import exceptions.TimeIntersectionException;
import tasks.Epic;
import tasks.Subtask;
import tasks.Task;
@@ -10,14 +13,14 @@
import java.util.stream.Collectors;
public class InMemoryTaskManager implements TaskManager {
- private final Map taskList;
- private final Map epicList;
- private final Map subtaskList;
- private Integer idMain = 0;
+ protected final Map taskList;
+ protected final Map epicList;
+ protected final Map subtaskList;
+ private Integer idMain = 1;
private final Map tasksSortedByTime;
private final HistoryManager viewHistory = Managers.getDefaultHistory();
- // компаратор для упоорядочивания задач по ремени запуска,
+ // Компаратор для упоорядочивания задач по ремени запуска,
// а при совпадении по возрастанию идентификатора.
// Задачи с временем null помещаются в начало.
private final Comparator taskComparator = Comparator.comparing(Task::getStartTime,
@@ -33,10 +36,24 @@ public InMemoryTaskManager() {
// Метод добавления новой задачи
@Override
- public int addNewTask(Task newTask) {
+ public int addNewTask(Task newTask) throws TimeIntersectionException {
if (newTask == null) {
return -1;
}
+ if (newTask.getStartTime() == null) {
+ return -2; // Время начала выполнения задачи обязательный параметр
+ }
+ if (newTask.getStatus() == null) {
+ newTask.setStatus(TaskStatus.NEW);
+ }
+ if (newTask.getDuration() == null) {
+ newTask.setDuration(Duration.ofMinutes(15));
+ }
+ int intersections = getTaskIntersectionsNum(newTask);
+ if (intersections > 0) {
+ String message = "Конфликт по времени исполнения. Новая задача:\n " + newTask.toString();
+ throw new TimeIntersectionException(message, "число конфликтов - " + intersections);
+ }
Integer id = idMain++;
newTask.setId(id);
taskList.put(id, newTask);
@@ -58,14 +75,28 @@ public int addNewEpic(Epic newEpic) {
// Метод добавления новой подзадачи
@Override
- public int addNewSubtask(Subtask newSubtask) {
+ public int addNewSubtask(Subtask newSubtask) throws TimeIntersectionException {
if (newSubtask == null) {
return -1;
}
+ if (newSubtask.getStartTime() == null) {
+ return -2; // Время начала выполнения задачи обязательный параметр
+ }
+ if (newSubtask.getStatus() == null) {
+ newSubtask.setStatus(TaskStatus.NEW);
+ }
+ if (newSubtask.getDuration() == null) {
+ newSubtask.setDuration(Duration.ofMinutes(15));
+ }
Epic epic = epicList.get(newSubtask.getEpicId());
if (epic == null) {
return -2;
}
+ int intersections = getTaskIntersectionsNum(newSubtask);
+ if (intersections > 0) {
+ String message = "Конфликт по времени исполнения. Новая подзадача:\n " + newSubtask.toString();
+ throw new TimeIntersectionException(message, "число конфликтов - " + intersections);
+ }
Integer id = idMain++;
newSubtask.setId(id);
subtaskList.put(id, newSubtask);
@@ -83,31 +114,51 @@ public int getNumberOfObjects() {
// Метод получения задачи по индексу
@Override
- public Task getTask(Integer id) {
+ public Task getTask(Integer id) throws NotFoundException {
Task task = taskList.get(id);
+ if (task == null) {
+ throw new NotFoundException("Задача не найдена", "id=" + id);
+ }
viewHistory.add(task);
return task;
}
// Метод получения эпика по индексу
@Override
- public Epic getEpic(Integer id) {
+ public Epic getEpic(Integer id) throws NotFoundException {
Epic epic = epicList.get(id);
+ if (epic == null) {
+ throw new NotFoundException("Эпик не найден", "id=" + id);
+ }
viewHistory.add(epic);
return epic;
}
// Метод получения подзадачи по индексу
@Override
- public Subtask getSubtask(Integer id) {
+ public Subtask getSubtask(Integer id) throws NotFoundException {
Subtask s = subtaskList.get(id);
+ if (s == null) {
+ throw new NotFoundException("Подзадача не найдена", "id=" + id);
+ }
viewHistory.add(s);
return s;
}
// Метод обновления задачи
@Override
- public int updateTask(Task task) {
+ public int updateTask(Task task) throws TimeIntersectionException {
+ if (task.getStatus() == null) {
+ task.setStatus(TaskStatus.NEW);
+ }
+ if (task.getDuration() == null) {
+ task.setDuration(Duration.ofMinutes(15));
+ }
+ int intersections = getTaskIntersectionsNum(task);
+ if (intersections > 0) {
+ String message = "Конфликт по времени исполнения. Обновление задачи:\n " + task.toString();
+ throw new TimeIntersectionException(message, "число конфликтов - " + intersections);
+ }
int id = task.getId();
taskList.put(id, task);
addTaskToSortedMap(task);
@@ -118,6 +169,14 @@ public int updateTask(Task task) {
@Override
public int updateEpic(Epic newEpic) {
int id = newEpic.getId();
+ Epic oldEpic = epicList.get(id);
+ if (oldEpic != null) {
+ // перепмсываум идентификаторы подзадач старого эппика в новый
+ for (Integer idSubtask : oldEpic.getSubtasks()) {
+ newEpic.addSubtask(idSubtask);
+ }
+ }
+ // заменяем старый эпик на новый
epicList.put(id, newEpic);
newEpic.reloadSubtakList(getEpic(id).getSubtasks());
setStatusEpic(id);
@@ -134,7 +193,18 @@ public int updateEpic(Epic newEpic) {
* @return - id обновленно подзадачи, или меньше нуля если произошла ошибка
*/
@Override
- public int updateSubtask(Subtask newSubtask) {
+ public int updateSubtask(Subtask newSubtask) throws TimeIntersectionException {
+ if (newSubtask.getStatus() == null) {
+ newSubtask.setStatus(TaskStatus.NEW);
+ }
+ if (newSubtask.getDuration() == null) {
+ newSubtask.setDuration(Duration.ofMinutes(15));
+ }
+ int intersections = getTaskIntersectionsNum(newSubtask);
+ if (intersections > 0) {
+ String message = "Конфликт по времени исполнения. Обновление подзадачи:\n " + newSubtask.toString();
+ throw new TimeIntersectionException(message, "число конфликтов - " + intersections);
+ }
int id = newSubtask.getId();
int epicId = newSubtask.getEpicId();
if (!epicList.containsKey(epicId)) {
@@ -158,7 +228,7 @@ private void setStatusEpic(Integer epicId) {
Epic epic = epicList.get(epicId);
setEpicTime(epicId);
- if (epic.getSubtasks().isEmpty()) {
+ if (subtaskList.isEmpty() || epic.getSubtasks().isEmpty()) {
epic.setStatus(TaskStatus.NEW);
return;
}
@@ -194,8 +264,12 @@ private void setStatusEpic(Integer epicId) {
@Override
- public void removeTask(Integer taskId) {
+ public void removeTask(Integer taskId) throws NotFoundException {
Task task = taskList.get(taskId);
+ if (task == null) {
+ throw new NotFoundException("Задача не найдена",
+ "id=" + taskId);
+ }
tasksSortedByTime.remove(task);
taskList.remove(taskId);
viewHistory.remove(taskId);
@@ -207,9 +281,9 @@ public void removeTask(Integer taskId) {
* @param epicId- идентификатор объекта
*/
@Override
- public void removeEpic(Integer epicId) {
+ public void removeEpic(Integer epicId) throws NotFoundException {
if (!epicList.containsKey(epicId)) {
- return;
+ throw new NotFoundException("Эпик не найден", "id=" + epicId);
}
for (Integer idSubtask : epicList.get(epicId).getSubtasks()) {
Task task = subtaskList.get(idSubtask);
@@ -223,13 +297,17 @@ public void removeEpic(Integer epicId) {
/**
* Удаление подзадачи по идентификатору
- * Удаляем предварительно из спика соответствующего эпика
+ * удаляем предварительно из спика соответствующего эпика
* и из общего списка позадач.
*
* @param subtaskId - идентификатор подзадачи
*/
@Override
- public void removeSubtask(Integer subtaskId) {
+ public void removeSubtask(Integer subtaskId) throws NotFoundException {
+ if (subtaskList.isEmpty()) {
+ throw new NotFoundException("подзадача не найдена",
+ "id=" + subtaskId);
+ }
Task task = subtaskList.get(subtaskId);
tasksSortedByTime.remove(task);
@@ -241,17 +319,26 @@ public void removeSubtask(Integer subtaskId) {
}
@Override
- public List getTaskList() {
+ public List getTaskList() throws NotFoundException {
+ if (taskList.isEmpty()) {
+ throw new NotFoundException("Информация не найдена.", "Список задач пуст.");
+ }
return new ArrayList<>(taskList.values());
}
@Override
- public List getEpicList() {
+ public List getEpicList() throws NotFoundException {
+ if (epicList.isEmpty()) {
+ throw new NotFoundException("Информация не найдена.", "Список эпиков пуст.");
+ }
return new ArrayList<>(epicList.values());
}
@Override
- public ArrayList getSubtaskList() {
+ public ArrayList getSubtaskList() throws NotFoundException {
+ if (subtaskList.isEmpty()) {
+ throw new NotFoundException("Информация не найдена.", "Список лодзадач пуст.");
+ }
return new ArrayList<>(subtaskList.values());
}
@@ -278,7 +365,7 @@ public void removeAllEpics() {
// Удаление всех объектов класса Subtask
@Override
public void removeAllSubtasks() {
- for (Epic epic : getEpicList()) {
+ for (Epic epic : epicList.values()) {
epic.removeAllSubtasks();
}
for (Subtask subtask : subtaskList.values()) {
@@ -295,12 +382,15 @@ public void removeAllSubtasks() {
* @return - список подзадач
*/
@Override
- public List getSubtasksByEpic(Integer epicId) {
+ public List getSubtasksByEpic(Integer epicId) throws NotFoundException {
List subtasks = new ArrayList<>();
subtasks = subtaskList.values().stream()
.filter((Subtask subtask) -> subtask.getEpicId() == epicId)
.collect(Collectors.toList());
+ if (subtasks.isEmpty()) {
+ throw new NotFoundException("Информация не найдена.", "Список лодзадач пуст.");
+ }
return subtasks;
}
@@ -310,23 +400,32 @@ public List getSubtasksByEpic(Integer epicId) {
* @return - возвращает список использованных объектов
*/
@Override
- public List getHistory() {
+ public List getHistory() throws NotFoundException {
+ if (viewHistory.getHistory().isEmpty()) {
+ throw new NotFoundException("Информация не найдена.", "История отсутствует.");
+ }
return viewHistory.getHistory();
}
// очистка всех задач и эпиков
public void clear() {
- removeAllTasks();
- removeAllEpics();
- tasksSortedByTime.clear();
- idMain = 0;
+ if (!taskList.isEmpty()) {
+ removeAllTasks();
+ }
+ if (!epicList.isEmpty()) {
+ removeAllEpics();
+ }
+ if (!tasksSortedByTime.isEmpty()) {
+ tasksSortedByTime.clear();
+ }
+ idMain = 1;
}
/**
* Пересчет идентификатора задач после загрузки данных из файла
*/
public void resetMainId() {
- int maxId = 0;
+ int maxId = 1;
for (int i : taskList.keySet()) {
if (i > maxId) maxId = i;
}
@@ -387,8 +486,11 @@ private void setEpicTime(Integer epicId) {
* @return - отсортированный список
*/
@Override
- public List getPrioritizedTasks() {
+ public List getPrioritizedTasks() throws NotFoundException {
+ if (tasksSortedByTime.isEmpty()) {
+ throw new NotFoundException("Информация не найдена", "список задач пуст");
+ }
List sortedTaskList = new ArrayList<>();
for (Map.Entry entry : tasksSortedByTime.entrySet()) {
@@ -411,30 +513,37 @@ private void addTaskToSortedMap(Task task) {
*/
return;
}
-
LocalDateTime curentTime = LocalDateTime.now();
- if (tasksSortedByTime.size() == 0) {
- tasksSortedByTime.put(task, curentTime.format(Task.DATE_TIME_FORMATTER));
- return;
- }
-
- // Проверяем пересечение времени добавляемой задачи с существующими задачами
- List crossTime = getPrioritizedTasks().stream()
- .filter((Task existsTask) -> !checkTimeFree(task, existsTask))
- .collect(Collectors.toList());
-
- if (crossTime.isEmpty()) {
- tasksSortedByTime.put(task, curentTime.format(Task.DATE_TIME_FORMATTER));
- } else {
- String message = "Конфликт по времени исполнения.\n " + task.toString();
- throw new TaskCrossTimeException(message, "число конфликтов - " + crossTime.size());
- }
+ tasksSortedByTime.put(task, curentTime.format(Task.DATE_TIME_FORMATTER));
}
+ /**
+ * Удаление задачи из отсортированного списка
+ *
+ * @param task
+ */
private void removeFromSortedList(Task task) {
tasksSortedByTime.remove(task);
}
+ /**
+ * Проверка пересечения времени выполнения задачи с временами задач в отсортированном списке
+ *
+ * @param newTask - проверяемая задача
+ * @return - число пересечений по времени с существующими задачами
+ */
+ private int getTaskIntersectionsNum(Task newTask) {
+ // Проверяем пересечение времени добавляемой задачи с существующими задачами
+ if (tasksSortedByTime.isEmpty()) {
+ return 0;
+ }
+ List intersections = getPrioritizedTasks().stream()
+ .filter((Task existsTask) -> !checkTimeFree(newTask, existsTask))
+ .collect(Collectors.toList());
+
+ return intersections.size();
+ }
+
/**
* Определение непересечения временных интервалов двух задач
*
@@ -444,7 +553,7 @@ private void removeFromSortedList(Task task) {
*/
private boolean checkTimeFree(Task task1, Task task2) {
if (task1.equals(task2)) {
- return true;
+ return true; // пересечение с собой не учитываем (update)
}
LocalDateTime task1Start = task1.getStartTime();
LocalDateTime task1End = task1.getEndTime();
@@ -455,5 +564,4 @@ private boolean checkTimeFree(Task task1, Task task2) {
task2Start.isAfter(task1End);
}
-
}
\ No newline at end of file
diff --git a/src/Managers.java b/src/managers/Managers.java
similarity index 83%
rename from src/Managers.java
rename to src/managers/Managers.java
index 342e1c7..6156708 100644
--- a/src/Managers.java
+++ b/src/managers/Managers.java
@@ -1,3 +1,5 @@
+package managers;
+
public final class Managers {
// объект утилитарного класса не должен создаваться!
// конструктор объявлен с модификатором "private"
@@ -6,7 +8,8 @@ private Managers() {
// определение объекта меджера задач
public static TaskManager getDefault() {
- return new FileBackedTaskManager();
+ InMemoryTaskManager manager = new InMemoryTaskManager();
+ return manager;
}
// определение объекта журнала событий
diff --git a/src/TaskManager.java b/src/managers/TaskManager.java
similarity index 54%
rename from src/TaskManager.java
rename to src/managers/TaskManager.java
index 3dce9f8..3ebaa91 100644
--- a/src/TaskManager.java
+++ b/src/managers/TaskManager.java
@@ -1,3 +1,7 @@
+package managers;
+
+import exceptions.NotFoundException;
+import exceptions.TimeIntersectionException;
import tasks.Epic;
import tasks.Subtask;
import tasks.Task;
@@ -6,42 +10,42 @@
public interface TaskManager {
// Метод добавления новой задачи
- int addNewTask(Task newTask);
+ int addNewTask(Task newTask) throws TimeIntersectionException;
// Метод добавления нового эпика
int addNewEpic(Epic newEpic);
// Метод добавления новоq подзадачи
- int addNewSubtask(Subtask newSubtask);
+ int addNewSubtask(Subtask newSubtask) throws TimeIntersectionException;
// Метод получения задачи по индексу
- Task getTask(Integer id);
+ Task getTask(Integer id) throws NotFoundException;
// Метод получения эпика по индексу
- Epic getEpic(Integer id);
+ Epic getEpic(Integer id) throws NotFoundException;
// Метод получения подзадачи по индексу
- Subtask getSubtask(Integer id);
+ Subtask getSubtask(Integer id) throws NotFoundException;
// Метод обновления задачи
- int updateTask(Task task);
+ int updateTask(Task task) throws TimeIntersectionException;
// Метод обновления эпика
int updateEpic(Epic newEpic);
- int updateSubtask(Subtask newSubtask);
+ int updateSubtask(Subtask newSubtask) throws TimeIntersectionException;
- void removeTask(Integer taskId);
+ void removeTask(Integer taskId) throws NotFoundException;
- void removeEpic(Integer epicId);
+ void removeEpic(Integer epicId) throws NotFoundException;
- void removeSubtask(Integer subtaskId);
+ void removeSubtask(Integer subtaskId) throws NotFoundException;
- List getTaskList();
+ List getTaskList() throws NotFoundException;
- List getEpicList();
+ List getEpicList() throws NotFoundException;
- List getSubtaskList();
+ List getSubtaskList() throws NotFoundException;
// Удаление всех объектов класса Task
void removeAllTasks();
@@ -58,7 +62,7 @@ public interface TaskManager {
int getNumberOfObjects();
// просмотр использованных задач
- List getHistory();
+ List getHistory() throws NotFoundException;
- List getPrioritizedTasks();
+ List getPrioritizedTasks() throws NotFoundException;
}
diff --git a/src/tasks/Epic.java b/src/tasks/Epic.java
index f649043..4eb50db 100644
--- a/src/tasks/Epic.java
+++ b/src/tasks/Epic.java
@@ -1,31 +1,30 @@
package tasks;
-import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
public class Epic extends Task {
- private List subtaskList;
+ private List subtasks;
private LocalDateTime endTime;
- private Duration duration;
// конструктор с параметрами "имя", "описание"
public Epic(String title, String description) {
super(title, description);
- subtaskList = new ArrayList<>();
+ subtasks = new ArrayList<>();
}
// конструктор с одним параметром "имя"
public Epic(String title) {
super(title);
- subtaskList = new ArrayList<>();
+ subtasks = new ArrayList<>();
}
// Конструктор копирования объекта
public Epic(Epic original) {
super(original);
- subtaskList = new ArrayList<>(original.getSubtasks());
+ subtasks = new ArrayList<>(original.getSubtasks());
}
// Переопределяем метод отображения объекта
@@ -50,44 +49,44 @@ public String toString() {
result += ", title='" + getTitle() + '\'' +
", description='" + getDescription() + '\'' +
", status=" + getStatus() +
- ", subtaskNumber=" + subtaskList.size() +
+ ", subtasks=" + Arrays.toString(subtasks.toArray()) +
'}';
return result;
}
// получение списка идентификаторов подзадач
public ArrayList getSubtasks() {
- return new ArrayList<>(subtaskList);
+ return new ArrayList<>(subtasks);
}
// метод добавления идентификатора подзадачи в список эпика
public void addSubtask(Integer subtaskId) {
- int index = subtaskList.indexOf(subtaskId);
+ int index = subtasks.indexOf(subtaskId);
// Если идентификатор уже существует или равен идентификатору эпика
// выходим без добавления задачи
if ((index >= 0) || (subtaskId == getId())) return;
- subtaskList.add(subtaskId);
+ subtasks.add(subtaskId);
}
// Удаление идентификатора подзадачи из списка эпика
public void removeSubtask(Integer subtaskId) {
- int index = subtaskList.indexOf(subtaskId);
+ int index = subtasks.indexOf(subtaskId);
if (index < 0) {
return;
}
- subtaskList.remove(index);
+ subtasks.remove(index);
}
public void removeAllSubtasks() {
- subtaskList.clear();
+ subtasks.clear();
setStatus(TaskStatus.NEW);
}
// метод переписывания списка подзадач, массивом новых идентификаторов
- public void reloadSubtakList(ArrayList newSubtaskList) {
- subtaskList.clear();
- subtaskList.addAll(newSubtaskList);
+ public void reloadSubtakList(ArrayList newsubtasks) {
+ subtasks.clear();
+ subtasks.addAll(newsubtasks);
}
@Override
@@ -98,13 +97,5 @@ public LocalDateTime getEndTime() {
public void setEndTime(LocalDateTime endTime) {
this.endTime = endTime;
}
-/*
- @Override
- public Duration getDuration() {
- if (subtaskList.isEmpty()) {
- return null;
- }
- return duration;
- }
-*/
+
}
diff --git a/src/tasks/Task.java b/src/tasks/Task.java
index 15d042e..7f201e1 100644
--- a/src/tasks/Task.java
+++ b/src/tasks/Task.java
@@ -4,10 +4,11 @@
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
+
public class Task {
public static final DateTimeFormatter DATE_TIME_FORMATTER =
DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm");
- private final String title; // заголовок задачи не меняется в течении жизни
+ private String title;
private String description;
private int id;
private TaskStatus status;
@@ -105,6 +106,10 @@ public int hashCode() {
return hash + id;
}
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
// методчтения заголовка задачи
// Во избежание путаниц заголовок задачи задается только в конструкторе
public String getTitle() {
diff --git a/test/httpapi/HttpEpicsHandlerTest.java b/test/httpapi/HttpEpicsHandlerTest.java
new file mode 100644
index 0000000..ffa72e7
--- /dev/null
+++ b/test/httpapi/HttpEpicsHandlerTest.java
@@ -0,0 +1,287 @@
+package httpapi;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+import com.google.gson.reflect.TypeToken;
+import managers.InMemoryTaskManager;
+import managers.TaskManager;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import tasks.Epic;
+import tasks.Subtask;
+
+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 HttpEpicsHandlerTest {
+ TaskManager manager = new InMemoryTaskManager();
+ HttpTaskServer taskServer = new HttpTaskServer(manager);
+
+ @BeforeEach
+ void setUp() throws IOException {
+ manager.removeAllTasks();
+ manager.removeAllEpics();
+ taskServer.start();
+ }
+
+ @AfterEach
+ void tearDown() {
+ taskServer.stop();
+ }
+
+ /**
+ * Тестируем добавление эпика
+ */
+ @Test
+ public void testAddEpic() throws IOException, InterruptedException {
+ Epic epic = new Epic("Test AddEpic",
+ "Teting AddNewEpic");
+
+ String epicJson = HttpTaskServer.gson.toJson(epic);
+
+ // создаём HTTP-клиент и запрос
+ HttpClient client = HttpClient.newHttpClient();
+ URI url = URI.create("http://localhost:8080/epics");
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(url)
+ .POST(HttpRequest.BodyPublishers.ofString(epicJson)).build();
+
+ // обработчик запроса с конвертацией тела запроса в строку
+ HttpResponse response = client.send(request,
+ HttpResponse.BodyHandlers.ofString());
+
+ // проверяем код ответа
+ assertEquals(201, response.statusCode(),
+ "Добавление эпика: неожиданный код ответа сервера");
+
+ // проверяем, что создался один эпик с корректным именем
+ List epicsFromManager = manager.getEpicList();
+
+ assertNotNull(epicsFromManager,
+ "Эпик не создан");
+ assertEquals(1, epicsFromManager.size(),
+ "Некорректное количество эпиков");
+ assertEquals("Test AddEpic", epicsFromManager.get(0).getTitle(),
+ "Некорректное имя эпика");
+
+ }
+
+ /**
+ * Тестируем обновление информации об эпике через HTTP сервер
+ */
+ @Test
+ public void testUpdateEpic() throws IOException, InterruptedException {
+ makeEpicList(1);
+
+ Epic epic = new Epic("Test UpdateEpic",
+ "Teting AddNewEpic");
+
+ String epicJson = HttpTaskServer.gson.toJson(epic);
+
+ // создаём HTTP-клиент и запрос
+ HttpClient client = HttpClient.newHttpClient();
+ URI url = URI.create("http://localhost:8080/epics/1");
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(url)
+ .POST(HttpRequest.BodyPublishers.ofString(epicJson)).build();
+
+ // обработчик запроса с конвертацией тела запроса в строку
+ HttpResponse response = client.send(request,
+ HttpResponse.BodyHandlers.ofString());
+
+ // проверяем код ответа
+ assertEquals(201, response.statusCode(),
+ "Обновление эпика: неожиданный код ответа сервера");
+
+ List epicsFromManager = manager.getEpicList();
+
+ assertNotNull(epicsFromManager,
+ "Эпик не создан");
+ assertEquals(1, epicsFromManager.size(),
+ "Некорректное количество эпиков");
+ assertEquals("Test UpdateEpic", epicsFromManager.get(0).getTitle(),
+ "Эпик не обновлен");
+ }
+
+ /**
+ * Тестируем чтение эпика через HTTP сервер
+ */
+ @Test
+ public void tetGetEpic() throws IOException, InterruptedException {
+ makeEpicList(1);
+
+ // создаём HTTP-клиент и запрос
+ HttpClient client = HttpClient.newHttpClient();
+ URI url = URI.create("http://localhost:8080/epics/1");
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(url).GET().build();
+
+ // обработчик запроса с конвертацией тела запроса в строку
+ HttpResponse response = client.send(request,
+ HttpResponse.BodyHandlers.ofString());
+ // проверяем код ответа
+ assertEquals(200, response.statusCode(),
+ "Чтение эпика: неожиданный код ответа сервера");
+
+ if (response.statusCode() == 200) {
+ JsonElement jsonElement = JsonParser.parseString(response.body());
+ assertTrue(jsonElement.isJsonObject(),
+ "Ошибка чтения ответа сервера.");
+ Epic newEpic = null;
+ newEpic = HttpTaskServer.gson.fromJson(jsonElement, Epic.class);
+ assertNotNull(newEpic, "Ошибка десериализации эпика.");
+ assertEquals(1, newEpic.getId(),
+ "Неожиданный идентификатор эпика");
+ }
+ }
+
+ /**
+ * Вспомогательный класс определение типа объекта десериализации
+ */
+ class EpicListTypeToken extends TypeToken> {
+ }
+
+ class SubtaskListTypeToken extends TypeToken> {
+ }
+
+ /**
+ * Тестируем чтение списка эпиков черех HTTP сервер
+ */
+ @Test
+ public void testGetEpics() throws IOException, InterruptedException {
+ makeEpicList(3);
+
+ // создаём HTTP-клиент и запрос
+ HttpClient client = HttpClient.newHttpClient();
+ URI url = URI.create("http://localhost:8080/epics");
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(url).GET().build();
+
+ // обработчик запроса с конвертацией тела запроса в строку
+ HttpResponse response = client.send(request,
+ HttpResponse.BodyHandlers.ofString());
+ // проверяем код ответа
+ assertEquals(200, response.statusCode(),
+ "Чтение эпика: неожиданный код ответа сервера");
+
+ if (response.statusCode() == 200) {
+ List epicListFromServer = HttpTaskServer.gson.fromJson(response.body(), new EpicListTypeToken().getType());
+
+ assertNotNull(epicListFromServer,
+ "Список эпиков не прочитан.");
+
+ int expectedSize = manager.getEpicList().size();
+ assertEquals(expectedSize, epicListFromServer.size(),
+ "Список эпиков не полный.");
+ }
+ }
+
+ /**
+ * Тестируем удаление эпика
+ */
+ @Test
+ public void testDeleteEpic() throws IOException, InterruptedException {
+ makeEpicList(3);
+
+ // создаём HTTP-клиент и запрос
+ HttpClient client = HttpClient.newHttpClient();
+ URI url = URI.create("http://localhost:8080/epics/2");
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(url).DELETE().build();
+
+ // обработчик запроса с конвертацией тела запроса в строку
+ HttpResponse response = client.send(request,
+ HttpResponse.BodyHandlers.ofString());
+ // проверяем код ответа
+ assertEquals(200, response.statusCode(),
+ "Удаление эпика: неожиданный код ответа сервера");
+
+ assertEquals(2, manager.getEpicList().size(),
+ "Неверная длина списка эпиков после удаления.");
+ }
+
+ /**
+ * Тестируем чтение подзадач эпика.
+ */
+ @Test
+ public void testGetSubtasksByEpic() throws IOException, InterruptedException {
+ makeEpicList(3);
+ manager.addNewSubtask(new Subtask(2,
+ "test Subtask1", "-",
+ LocalDateTime.now(),
+ Duration.ofMinutes(15)));
+ manager.addNewSubtask(new Subtask(2,
+ "test Subtask2", "-",
+ LocalDateTime.now().plusMinutes(20),
+ Duration.ofMinutes(15)));
+
+ // создаём HTTP-клиент и запрос
+ HttpClient client = HttpClient.newHttpClient();
+ URI url = URI.create("http://localhost:8080/epics/2/subtasks");
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(url).GET().build();
+
+ // обработчик запроса с конвертацией тела запроса в строку
+ HttpResponse response = client.send(request,
+ HttpResponse.BodyHandlers.ofString());
+ // проверяем код ответа
+ assertEquals(200, response.statusCode(),
+ "Чтение подзадач эпика: неожиданный код ответа сервера");
+
+ if (response.statusCode() == 200) {
+ List subtasksListFromServer = HttpTaskServer.gson.fromJson(response.body(), new SubtaskListTypeToken().getType());
+
+ assertNotNull(subtasksListFromServer,
+ "Список подзадач эпика не прочитан.");
+
+ int expectedSize = manager.getSubtasksByEpic(2).size();
+ assertEquals(expectedSize, subtasksListFromServer.size(),
+ "Список подзадач эпика не полный.");
+ }
+ }
+
+ /**
+ * Тестируем ошибку 404
+ */
+ @Test
+ public void testError404() throws IOException, InterruptedException {
+ // создаём HTTP-клиент и запрос
+ HttpClient client = HttpClient.newHttpClient();
+ URI url = URI.create("http://localhost:8080/epics/100");
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(url).GET().build();
+
+ // обработчик запроса с конвертацией тела запроса в строку
+ HttpResponse response = client.send(request,
+ HttpResponse.BodyHandlers.ofString());
+ // проверяем код ответа
+ assertEquals(404, response.statusCode(),
+ "Чтение несуществующего эпика: неожиданный код ответа сервера");
+ }
+
+ /**
+ * Создание заданного числа эпиков в менеджере
+ *
+ * @param size - число эпиков
+ */
+ private void makeEpicList(int size) {
+ if(size == 0) {
+ return;
+ }
+ for (int i = 0; i < size; i ++) {
+ manager.addNewEpic(new Epic("epicList element:" + i,
+ "Testing epicList"));
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/test/httpapi/HttpHistoryHandlerTest.java b/test/httpapi/HttpHistoryHandlerTest.java
new file mode 100644
index 0000000..8d2f6a5
--- /dev/null
+++ b/test/httpapi/HttpHistoryHandlerTest.java
@@ -0,0 +1,93 @@
+package httpapi;
+
+import com.google.gson.reflect.TypeToken;
+import managers.InMemoryTaskManager;
+import managers.TaskManager;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import tasks.Epic;
+import tasks.Subtask;
+import tasks.Task;
+
+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.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+class HttpHistoryHandlerTest {
+ TaskManager manager = new InMemoryTaskManager();
+ HttpTaskServer taskServer = new HttpTaskServer(manager);
+
+ @BeforeEach
+ void setUp() throws IOException {
+ manager.removeAllTasks();
+ manager.removeAllEpics();
+ taskServer.start();
+ }
+
+ @AfterEach
+ void tearDown() {
+ taskServer.stop();
+ }
+
+ /**
+ * Вспомогательный класс определение типа объекта десериализации
+ */
+ class HistoryListTypeToken extends TypeToken> {
+ }
+
+ /**
+ * Тестируем получение истории оюращения к задачам
+ */
+ @Test
+ public void testHistory() throws IOException, InterruptedException {
+ int taskId = manager.addNewTask(new Task("Test AddTask",
+ "Testing AddTask",
+ LocalDateTime.now(),
+ Duration.ofMinutes(15)));
+
+ int epicId = manager.addNewEpic(new Epic("Test subtask epic",
+ "Epic for testing Sabtask"));
+
+ int subtaskId = manager.addNewSubtask(new Subtask(epicId, "Test AddSubtask", "-",
+ LocalDateTime.now().plusMinutes(30),
+ Duration.ofMinutes(15)));
+
+ Task task = manager.getTask(taskId);
+ Epic epic = manager.getEpic(epicId);
+ Subtask subtask = manager.getSubtask(subtaskId);
+
+ // создаём HTTP-клиент и запрос
+ HttpClient client = HttpClient.newHttpClient();
+ URI url = URI.create("http://localhost:8080/history");
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(url).GET().build();
+
+ // обработчик запроса с конвертацией тела запроса в строку
+ HttpResponse response = client.send(request,
+ HttpResponse.BodyHandlers.ofString());
+ // проверяем код ответа
+ assertEquals(200, response.statusCode(),
+ "Чтение истории задач: неожиданный код ответа сервера");
+
+ if (response.statusCode() == 200) {
+ List historyFromServer = HttpTaskServer.gson.fromJson(response.body(),
+ new HistoryListTypeToken().getType());
+
+ assertNotNull(historyFromServer,
+ "история не прочитана.");
+
+ int expectedSize = manager.getHistory().size();
+ assertEquals(expectedSize, historyFromServer.size(),
+ "Список истории не полный.");
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/httpapi/HttpPrioritizedHandlerTest.java b/test/httpapi/HttpPrioritizedHandlerTest.java
new file mode 100644
index 0000000..130db8e
--- /dev/null
+++ b/test/httpapi/HttpPrioritizedHandlerTest.java
@@ -0,0 +1,104 @@
+package httpapi;
+
+import com.google.gson.reflect.TypeToken;
+import managers.InMemoryTaskManager;
+import managers.TaskManager;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import tasks.Epic;
+import tasks.Subtask;
+import tasks.Task;
+
+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 HttpPrioritizedHandlerTest {
+ TaskManager manager = new InMemoryTaskManager();
+ HttpTaskServer taskServer = new HttpTaskServer(manager);
+
+ @BeforeEach
+ void setUp() throws IOException {
+ manager.removeAllTasks();
+ manager.removeAllEpics();
+ taskServer.start();
+ }
+
+ @AfterEach
+ void tearDown() {
+ taskServer.stop();
+ }
+
+ /**
+ * Вспомогательный класс определение типа объекта десериализации
+ */
+ class PrioritizedTypeToken extends TypeToken> {
+ }
+
+ /**
+ * тестируем получение хронологического списка
+ */
+ @Test
+ public void testPrioritizedList() throws IOException, InterruptedException {
+ manager.addNewTask(new Task("Test AddTask1",
+ "Testing AddTask",
+ LocalDateTime.now(),
+ Duration.ofMinutes(15)));
+
+ int epicId = manager.addNewEpic(new Epic("Test subtask epic",
+ "Epic for testing Sabtask"));
+
+ manager.addNewSubtask(new Subtask(epicId, "Test AddSubtask2", "-",
+ LocalDateTime.now().plusMinutes(30),
+ Duration.ofMinutes(15)));
+
+ manager.addNewTask(new Task("Test AddTask2",
+ "Testing AddTask2",
+ LocalDateTime.now().plusMinutes(80),
+ Duration.ofMinutes(15)));
+
+ manager.addNewSubtask(new Subtask(epicId, "Test AddSubtask2", "-",
+ LocalDateTime.now().plusMinutes(50),
+ Duration.ofMinutes(15)));
+
+ // создаём HTTP-клиент и запрос
+ HttpClient client = HttpClient.newHttpClient();
+ URI url = URI.create("http://localhost:8080/prioritized");
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(url).GET().build();
+
+ // обработчик запроса с конвертацией тела запроса в строку
+ HttpResponse response = client.send(request,
+ HttpResponse.BodyHandlers.ofString());
+ // проверяем код ответа
+ assertEquals(200, response.statusCode(),
+ "Чтение хронологии задач: неожиданный код ответа сервера");
+
+ if (response.statusCode() == 200) {
+ List prioritizedFromServer = HttpTaskServer.gson.fromJson(response.body(),
+ new PrioritizedTypeToken().getType());
+
+ assertNotNull(prioritizedFromServer,
+ "Хронология не прочитана.");
+
+ int expectedSize = manager.getPrioritizedTasks().size();
+ assertEquals(expectedSize, prioritizedFromServer.size(),
+ "хронологический cписок не полный.");
+
+ // проверяем хронологическую последовательность полученного списка задач
+ for (int i = 0; i < (prioritizedFromServer.size() - 1); i++) {
+ assertTrue(prioritizedFromServer.get(i).getEndTime()
+ .isBefore(prioritizedFromServer.get(i + 1).getStartTime()),
+ "Нарушена хронология задач");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/httpapi/HttpSubtasksHandlerTest.java b/test/httpapi/HttpSubtasksHandlerTest.java
new file mode 100644
index 0000000..2e6cef6
--- /dev/null
+++ b/test/httpapi/HttpSubtasksHandlerTest.java
@@ -0,0 +1,292 @@
+package httpapi;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+import com.google.gson.reflect.TypeToken;
+import managers.InMemoryTaskManager;
+import managers.TaskManager;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import tasks.Epic;
+import tasks.Subtask;
+
+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 HttpSubtasksHandlerTest {
+ TaskManager manager = new InMemoryTaskManager();
+ HttpTaskServer taskServer = new HttpTaskServer(manager);
+
+ @BeforeEach
+ void setUp() throws IOException {
+ manager.removeAllTasks();
+ manager.removeAllEpics();
+ taskServer.start();
+ }
+
+ @AfterEach
+ void tearDown() {
+ taskServer.stop();
+ }
+
+ /**
+ * Тестируем создание подзадачи через HTTP сервер
+ */
+ @Test
+ public void testAddSubtask() throws IOException, InterruptedException {
+
+ int epicId = manager.addNewEpic(new Epic("Test subtask epic",
+ "Epic for testing Sabtask"));
+
+ Subtask subtask = new Subtask(epicId, "Test AddSubtask", "-",
+ LocalDateTime.now(),
+ Duration.ofMinutes(15));
+
+ String subtaskJson = HttpTaskServer.gson.toJson(subtask);
+
+ // создаём HTTP-клиент и запрос
+ HttpClient client = HttpClient.newHttpClient();
+ URI url = URI.create("http://localhost:8080/subtasks");
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(url)
+ .POST(HttpRequest.BodyPublishers.ofString(subtaskJson)).build();
+
+ // обработчик запроса с конвертацией тела запроса в строку
+ HttpResponse response = client.send(request,
+ HttpResponse.BodyHandlers.ofString());
+
+ // проверяем код ответа
+ assertEquals(201, response.statusCode(),
+ "Добавление подзадачи: неожиданный код ответа сервера");
+
+ // проверяем, что создана подзадача с корректным именем
+ List subtasksFromManager = manager.getSubtaskList();
+
+ assertNotNull(subtasksFromManager,
+ "Подзадача не создана");
+ assertEquals(1, subtasksFromManager.size(),
+ "Некорректное количество подзадач");
+ assertEquals("Test AddSubtask", subtasksFromManager.get(0).getTitle(),
+ "Некорректное имя подзадачи");
+ }
+
+ /**
+ * Тестируем обновление подзадачи через HTTP сервер
+ */
+ @Test
+ public void tetUpdateSubtask() throws IOException, InterruptedException {
+ int epicId = manager.addNewEpic(new Epic("Test subtask epic",
+ "Epic for testing Sabtask"));
+
+ int subtaskId = manager.addNewSubtask(new Subtask(epicId, "Test UpdateSubtask",
+ "-",
+ LocalDateTime.now(),
+ Duration.ofMinutes(15)));
+
+ // создаем подзадачу с измененными данными для обновления
+ Subtask subtask = new Subtask(epicId, "Subtask Updated",
+ "subtask updated successfully",
+ LocalDateTime.now().plusMinutes(30),
+ Duration.ofMinutes(15));
+ subtask.setId(subtaskId);
+
+ String subtaskJson = HttpTaskServer.gson.toJson(subtask);
+
+ // создаём HTTP-клиент и запрос
+ HttpClient client = HttpClient.newHttpClient();
+ URI url = URI.create("http://localhost:8080/subtasks/" + subtaskId);
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(url)
+ .POST(HttpRequest.BodyPublishers.ofString(subtaskJson)).build();
+
+ // обработчик запроса с конвертацией тела запроса в строку
+ HttpResponse response = client.send(request,
+ HttpResponse.BodyHandlers.ofString());
+
+ // проверяем код ответа
+ assertEquals(201, response.statusCode(),
+ "обновление подзадачи: неожиданный код ответа сервера");
+
+ // проверяем, что подзадача обновлена
+ List subtasksFromManager = manager.getSubtaskList();
+
+ assertNotNull(subtasksFromManager,
+ "Подзадача не создана");
+ assertEquals(1, subtasksFromManager.size(),
+ "Некорректное количество подзадач");
+ assertEquals("Subtask Updated", subtasksFromManager.get(0).getTitle(),
+ "Подзадача не обновилась");
+ }
+
+ /**
+ * Тестируем чтение подзадачи через HTTP сервер
+ */
+ @Test
+ public void testGetSubtask() throws IOException, InterruptedException {
+ makeSubtaskList(3);
+
+ // создаём HTTP-клиент и запрос
+ HttpClient client = HttpClient.newHttpClient();
+ URI url = URI.create("http://localhost:8080/subtasks/2");
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(url).GET().build();
+
+ // обработчик запроса с конвертацией тела запроса в строку
+ HttpResponse response = client.send(request,
+ HttpResponse.BodyHandlers.ofString());
+ // проверяем код ответа
+ assertEquals(200, response.statusCode(),
+ "Чтение подзадачи: неожиданный код ответа сервера");
+
+ if (response.statusCode() == 200) {
+ JsonElement jsonElement = JsonParser.parseString(response.body());
+ assertTrue(jsonElement.isJsonObject(),
+ "Ошибка чтения ответа сервера.");
+ Subtask newSubtask = null;
+ newSubtask = HttpTaskServer.gson.fromJson(jsonElement, Subtask.class);
+ assertNotNull(newSubtask, "Ошибка десериализации подзадачи.");
+ assertEquals(2, newSubtask.getId(),
+ "Неожиданный идентификатор подзадачи");
+ }
+ }
+
+ class SubtaskListTypeToken extends TypeToken> {
+ }
+
+ /**
+ * Тестируем чтение списка подзадач
+ */
+ @Test
+ public void testGetSubtasks() throws IOException, InterruptedException {
+ // создаем набор подзадач
+ makeSubtaskList(5);
+
+ // создаём HTTP-клиент и запрос
+ HttpClient client = HttpClient.newHttpClient();
+ URI url = URI.create("http://localhost:8080/subtasks");
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(url).GET().build();
+
+ // обработчик запроса с конвертацией тела запроса в строку
+ HttpResponse response = client.send(request,
+ HttpResponse.BodyHandlers.ofString());
+ // проверяем код ответа
+ assertEquals(200, response.statusCode(),
+ "Чтение подзадач: неожиданный код ответа сервера");
+
+ if (response.statusCode() == 200) {
+ List subtaskListFromServer = HttpTaskServer.gson.fromJson(response.body(),
+ new SubtaskListTypeToken().getType());
+
+ assertNotNull(subtaskListFromServer,
+ "Список подзадач не прочитан.");
+
+ int expectedSize = manager.getSubtaskList().size();
+ assertEquals(expectedSize, subtaskListFromServer.size(),
+ "Список подзадач не полный.");
+ }
+ }
+
+ /**
+ * Тестируем удаление подзадачи через HTTP сервер
+ */
+ @Test
+ public void testDeleteSubtask() throws IOException, InterruptedException {
+ makeSubtaskList(4);
+
+ // создаём HTTP-клиент и запрос
+ HttpClient client = HttpClient.newHttpClient();
+ URI url = URI.create("http://localhost:8080/subtasks/3");
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(url).DELETE().build();
+
+ // обработчик запроса с конвертацией тела запроса в строку
+ HttpResponse response = client.send(request,
+ HttpResponse.BodyHandlers.ofString());
+ // проверяем код ответа
+ assertEquals(200, response.statusCode(),
+ "удаление подзадачи: неожиданный код ответа сервера");
+
+ assertEquals(3, manager.getSubtaskList().size(),
+ "Неверная длина списка подзадач после удаления.");
+ }
+
+ /**
+ * Тестируем ошибку 404
+ */
+ @Test
+ public void testError404() throws IOException, InterruptedException {
+ // создаём HTTP-клиент и запрос
+ HttpClient client = HttpClient.newHttpClient();
+ URI url = URI.create("http://localhost:8080/subtasks/100");
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(url).GET().build();
+
+ // обработчик запроса с конвертацией тела запроса в строку
+ HttpResponse response = client.send(request,
+ HttpResponse.BodyHandlers.ofString());
+ // проверяем код ответа
+ assertEquals(404, response.statusCode(),
+ "Чтение несуществующей подзадачи: неожиданный код ответа сервера");
+ }
+
+ /**
+ * Тестируем ошибку 406
+ */
+ @Test
+ public void testError406() throws IOException, InterruptedException {
+ makeSubtaskList(3);
+
+ Subtask subtask = new Subtask(1, "Test timeIntersection Subtask",
+ "timeIntersection",
+ LocalDateTime.now(),
+ Duration.ofMinutes(15));
+
+ String subtaskJson = HttpTaskServer.gson.toJson(subtask);
+
+ // создаём HTTP-клиент и запрос
+ HttpClient client = HttpClient.newHttpClient();
+ URI url = URI.create("http://localhost:8080/subtasks");
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(url)
+ .POST(HttpRequest.BodyPublishers.ofString(subtaskJson)).build();
+
+ // обработчик запроса с конвертацией тела запроса в строку
+ HttpResponse response = client.send(request,
+ HttpResponse.BodyHandlers.ofString());
+
+ // проверяем код ответа
+ assertEquals(406, response.statusCode(),
+ "Подзадача в недопустимом интервале: неожиданный код ответа сервера");
+ }
+
+ /**
+ * Метод генерации заданного числа подзадач
+ *
+ * @param size - число подзадач для генерации
+ */
+ private void makeSubtaskList(int size) {
+ if (size == 0) {
+ return;
+ }
+ int epicId = manager.addNewEpic(new Epic("Test subtask epic",
+ "Epic for testing Sabtask"));
+
+ for (int i = 0; i < size; i++) {
+ manager.addNewSubtask(new Subtask(epicId,
+ "test Subtask:" + epicId + "." + (i + 1), "-",
+ LocalDateTime.now().plusMinutes(20 * i),
+ Duration.ofMinutes(15)));
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/httpapi/HttpTasksHandlerTest.java b/test/httpapi/HttpTasksHandlerTest.java
new file mode 100644
index 0000000..74109ad
--- /dev/null
+++ b/test/httpapi/HttpTasksHandlerTest.java
@@ -0,0 +1,321 @@
+package httpapi;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+import com.google.gson.reflect.TypeToken;
+import managers.InMemoryTaskManager;
+import managers.TaskManager;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import tasks.Task;
+
+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 HttpTasksHandlerTest {
+ TaskManager manager = new InMemoryTaskManager();
+ HttpTaskServer taskServer = new HttpTaskServer(manager);
+
+ public HttpTasksHandlerTest() {
+ }
+
+ @BeforeEach
+ void setUp() throws IOException {
+ manager.removeAllTasks();
+ manager.removeAllEpics();
+ taskServer.start();
+ }
+
+ @AfterEach
+ void tearDown() {
+ taskServer.stop();
+ }
+
+ /**
+ * Тестируем добавление задачи через Http сервер
+ */
+ @Test
+ public void testAddTask() throws IOException, InterruptedException {
+ Task task = new Task("Test AddTask",
+ "Testing AddTask",
+ LocalDateTime.now(),
+ Duration.ofMinutes(15));
+
+ String taskJson = HttpTaskServer.gson.toJson(task);
+
+ // создаём HTTP-клиент и запрос
+ HttpClient client = HttpClient.newHttpClient();
+ URI url = URI.create("http://localhost:8080/tasks");
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(url)
+ .POST(HttpRequest.BodyPublishers.ofString(taskJson)).build();
+
+ // обработчик запроса с конвертацией тела запроса в строку
+ HttpResponse response = client.send(request,
+ HttpResponse.BodyHandlers.ofString());
+ // проверяем код ответа
+ assertEquals(201, response.statusCode(),
+ "Добавление задачи: неожиданный код ответа сервера");
+
+ // проверяем, что создалась одна задача с корректным именем
+ List tasksFromManager = manager.getTaskList();
+
+ assertNotNull(tasksFromManager,
+ "Задача не создана");
+ assertEquals(1, tasksFromManager.size(),
+ "Некорректное количество задач");
+ assertEquals("Test AddTask", tasksFromManager.get(0).getTitle(),
+ "Некорректное имя задачи");
+ }
+
+ /**
+ * Тестируем обновление задачи через Http сервер
+ */
+ @Test
+ public void testUpdateTask() throws IOException, InterruptedException {
+ // добавляем задачу
+ makeTaskList(1);
+
+ Task task = new Task("Test UpdateTask",
+ "Testing UpdateTask",
+ LocalDateTime.now(),
+ Duration.ofMinutes(15));
+
+ String taskJson = HttpTaskServer.gson.toJson(task);
+
+ // создаём HTTP-клиент и запрос
+ HttpClient client = HttpClient.newHttpClient();
+ URI url = URI.create("http://localhost:8080/tasks/1");
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(url)
+ .POST(HttpRequest.BodyPublishers.ofString(taskJson)).build();
+
+ // обработчик запроса с конвертацией тела запроса в строку
+ HttpResponse response = client.send(request,
+ HttpResponse.BodyHandlers.ofString());
+ // проверяем код ответа
+ assertEquals(201, response.statusCode(),
+ "Обновление задачи: неожиданный код ответа сервера");
+
+ // читаем, задачу из хранилища
+ List tasksFromManager = manager.getTaskList();
+
+ assertNotNull(tasksFromManager,
+ "Задача не создана");
+ assertEquals(1, tasksFromManager.size(),
+ "Некорректное количество задач");
+ assertEquals("Test UpdateTask", tasksFromManager.get(0).getTitle(),
+ "Задача не обновилась.");
+
+ }
+
+ /**
+ * Тестируем чтение задачи по заданному идентификатору
+ */
+ @Test
+ public void testGetTask() throws IOException, InterruptedException {
+ // добавляем задачу
+ makeTaskList(1);
+
+ // создаём HTTP-клиент и запрос
+ HttpClient client = HttpClient.newHttpClient();
+ URI url = URI.create("http://localhost:8080/tasks/1");
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(url)
+ .GET()
+ .build();
+
+ // обработчик запроса с конвертацией тела запроса в строку
+ HttpResponse response = client.send(request,
+ HttpResponse.BodyHandlers.ofString());
+ // проверяем код ответа
+ assertEquals(200, response.statusCode(),
+ "Чтение задачи: неожиданный код ответа сервера");
+
+ if (response.statusCode() == 200) {
+ JsonElement jsonElement = JsonParser.parseString(response.body());
+ assertTrue(jsonElement.isJsonObject(),
+ "Ошибка чтения ответа сервера.");
+ Task newTask = null;
+ newTask = HttpTaskServer.gson.fromJson(jsonElement, Task.class);
+ assertNotNull(newTask, "Ошибка десериализации задачи.");
+ assertEquals(1, newTask.getId(),
+ "Неожиданный идентификатор задачи");
+ }
+ }
+
+ /**
+ * Вспомогательный класс определение типа объекта десериализации
+ */
+ class TaskListTypeToken extends TypeToken> {
+ }
+
+ /**
+ * Тестируем чтение списка задач через HTTP сервер
+ */
+ @Test
+ public void testGetTasks() throws IOException, InterruptedException {
+ // создаем список задач в менеджере
+ makeTaskList(3);
+
+ // создаём HTTP-клиент
+ HttpClient client = HttpClient.newHttpClient();
+ URI url = URI.create("http://localhost:8080/tasks");
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(url)
+ .GET()
+ .build();
+
+ HttpResponse response = client.send(request,
+ HttpResponse.BodyHandlers.ofString());
+ // проверяем код ответа
+ assertEquals(200, response.statusCode(),
+ "Чтение списка задач: неожиданный код ответа сервера");
+
+ if (response.statusCode() == 200) {
+ List taskListFromServer = HttpTaskServer.gson.fromJson(response.body(), new TaskListTypeToken().getType());
+
+ assertNotNull(taskListFromServer,
+ "Список задач не прочитан.");
+
+ int expectedSize = manager.getTaskList().size();
+ assertEquals(expectedSize, taskListFromServer.size(),
+ "Список задач не полный.");
+ }
+ }
+
+ /**
+ * Тестируем удаление задачи
+ */
+ @Test
+ public void testDelete() throws IOException, InterruptedException {
+ // создаем список задач
+ makeTaskList(3);
+
+ // создаём HTTP-клиент
+ HttpClient client = HttpClient.newHttpClient();
+ URI url = URI.create("http://localhost:8080/tasks/2");
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(url)
+ .DELETE()
+ .build();
+
+ HttpResponse response = client.send(request,
+ HttpResponse.BodyHandlers.ofString());
+ // проверяем код ответа
+ assertEquals(200, response.statusCode(),
+ "Удаление задачи: неожиданный код ответа сервера");
+
+ assertEquals(2, manager.getTaskList().size(),
+ "Неверная длина списка задач после удаления.");
+ }
+
+ /**
+ * Тестируем добавление задачи пересекающейся по времени
+ */
+ @Test
+ public void testTimeIntersection() throws IOException, InterruptedException {
+ // создаем список задач
+ makeTaskList(3);
+
+ // создаем задачу с текущим временем
+ Task task = new Task("Test TimeIntersection",
+ "Testing TimeIntersection",
+ LocalDateTime.now(),
+ Duration.ofMinutes(15));
+
+ String taskJson = HttpTaskServer.gson.toJson(task);
+
+ // создаём HTTP-клиент и запрос
+ HttpClient client = HttpClient.newHttpClient();
+ URI url = URI.create("http://localhost:8080/tasks");
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(url)
+ .POST(HttpRequest.BodyPublishers.ofString(taskJson)).build();
+
+ HttpResponse response = client.send(request,
+ HttpResponse.BodyHandlers.ofString());
+
+ assertEquals(406, response.statusCode(),
+ "Добавление пересекающейся задачи: неожиданный код ответа сервера");
+ assertEquals(3, manager.getTaskList().size(),
+ "Неверная длина списка задач.");
+ }
+
+ /**
+ * Тестируем ошибку 404
+ */
+ @Test
+ public void testError404() throws IOException, InterruptedException {
+ // создаём HTTP-клиент и запрос
+ HttpClient client = HttpClient.newHttpClient();
+ URI url = URI.create("http://localhost:8080/tasks/100");
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(url).GET().build();
+
+ // обработчик запроса с конвертацией тела запроса в строку
+ HttpResponse response = client.send(request,
+ HttpResponse.BodyHandlers.ofString());
+ // проверяем код ответа
+ assertEquals(404, response.statusCode(),
+ "Чтение несуществующей задачи: неожиданный код ответа сервера");
+ }
+
+ /**
+ * Тестируем ошибку 406
+ */
+ @Test
+ public void testError406() throws IOException, InterruptedException {
+ makeTaskList(3);
+
+ Task task = new Task("Test timeIntersection Task",
+ "timeIntersection",
+ LocalDateTime.now(),
+ Duration.ofMinutes(15));
+
+ String taskJson = HttpTaskServer.gson.toJson(task);
+
+ // создаём HTTP-клиент и запрос
+ HttpClient client = HttpClient.newHttpClient();
+ URI url = URI.create("http://localhost:8080/tasks");
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(url)
+ .POST(HttpRequest.BodyPublishers.ofString(taskJson)).build();
+
+ // обработчик запроса с конвертацией тела запроса в строку
+ HttpResponse response = client.send(request,
+ HttpResponse.BodyHandlers.ofString());
+
+ // проверяем код ответа
+ assertEquals(406, response.statusCode(),
+ "Задача в недопустимом интервале: неожиданный код ответа сервера");
+ }
+
+ /**
+ * Генерация набора задач в менеджере напрямую
+ *
+ * @param size - число генерируемых задач
+ */
+ private void makeTaskList(int size) {
+ if (size == 0) {
+ return;
+ }
+ for (int i = 0; i < size; i++) {
+ manager.addNewTask(new Task("taskList element:" + i,
+ "Testing taskList",
+ LocalDateTime.now().plusMinutes(20L * i),
+ Duration.ofMinutes(10)));
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/FileBackedTaskManagerTest.java b/test/managers/FileBackedTaskManagerTest.java
similarity index 95%
rename from test/FileBackedTaskManagerTest.java
rename to test/managers/FileBackedTaskManagerTest.java
index 37a6913..25de22c 100644
--- a/test/FileBackedTaskManagerTest.java
+++ b/test/managers/FileBackedTaskManagerTest.java
@@ -1,3 +1,5 @@
+package managers;
+
import exceptions.LoadException;
import exceptions.SaveException;
import org.junit.jupiter.api.AfterEach;
@@ -88,7 +90,7 @@ void loadFromFile() {
Duration.ofMinutes(15)));
// удаляем первую задачу что бы внести путаницу в идентификаторы
- manager.removeTask(0);
+ manager.removeTask(1);
tmpFile = new File(filename);
FileBackedTaskManager manager2 = FileBackedTaskManager.loadFromFile(tmpFile);
@@ -112,7 +114,7 @@ void loadFromFile() {
"task3",
LocalDateTime.now().plusMinutes(80),
Duration.ofMinutes(15)));
- assertEquals(4, taskId,
+ assertEquals(5, taskId,
"Некорректный счетчмк идентификаторов после загрузки файла.");
}
@@ -122,7 +124,10 @@ void loadFromFile() {
@Test
void saveAndLoadEmptyManager() {
int taskId = manager.addNewTask(new Task("Task 1",
- "Description task 1"));
+ "Description task 1",
+ LocalDateTime.now(),
+ Duration.ofMinutes(15)));
+
manager.removeTask(taskId);
assertEquals(0, manager.getNumberOfObjects(),
"Список задач не пуст.");
@@ -145,8 +150,11 @@ void loadEmptyFile() {
tmpFile.createNewFile(); // создаем пустой файл
manager2 = FileBackedTaskManager.loadFromFile(tmpFile);
assertNotNull(manager2, "Ошибка создания менеджера задач.");
+
int taskId = manager2.addNewTask(new Task("Task 1",
- "Description task 1"));
+ "Description task 1",
+ LocalDateTime.now(),
+ Duration.ofMinutes(15)));
assertEquals(1, manager2.getNumberOfObjects(),
"Ошибка работы с созданным менеджером.");
} catch (IOException e) {
diff --git a/test/InMemoryHistoryManagerTest.java b/test/managers/InMemoryHistoryManagerTest.java
similarity index 99%
rename from test/InMemoryHistoryManagerTest.java
rename to test/managers/InMemoryHistoryManagerTest.java
index a25b666..08911ca 100644
--- a/test/InMemoryHistoryManagerTest.java
+++ b/test/managers/InMemoryHistoryManagerTest.java
@@ -1,3 +1,5 @@
+package managers;
+
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
diff --git a/test/InMemoryTaskManagerTest.java b/test/managers/InMemoryTaskManagerTest.java
similarity index 92%
rename from test/InMemoryTaskManagerTest.java
rename to test/managers/InMemoryTaskManagerTest.java
index e5ca8c2..acfa700 100644
--- a/test/InMemoryTaskManagerTest.java
+++ b/test/managers/InMemoryTaskManagerTest.java
@@ -1,4 +1,6 @@
-import exceptions.TaskCrossTimeException;
+package managers;
+
+import exceptions.TimeIntersectionException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import tasks.Epic;
@@ -76,36 +78,40 @@ void timeConflict() {
"task2",
LocalDateTime.now().plusMinutes(10),
Duration.ofMinutes(20));
- assertThrows(TaskCrossTimeException.class,
+ assertThrows(TimeIntersectionException.class,
() -> {
manager.addNewTask(task);
},
- "Наложение времени задач должно приводить к исключению.");
+ "Наложение времени задач должно приводить к исключению.\n"
+ + task.toString());
// изменяем период задачи на перекрвыающий окончание существующей задачи
task.setStartTime(LocalDateTime.now().plusMinutes(30));
- assertThrows(TaskCrossTimeException.class,
+ assertThrows(TimeIntersectionException.class,
() -> {
manager.addNewTask(task);
},
- "Наложение времени задач должно приводить к исключению.");
+ "Наложение времени задач должно приводить к исключению.\n"
+ + task.toString());
// изменяем период задачи на вложенный во время выполнения существующей задачи
task.setDuration(Duration.ofMinutes(5));
- assertThrows(TaskCrossTimeException.class,
+ assertThrows(TimeIntersectionException.class,
() -> {
manager.addNewTask(task);
},
- "Наложение времени задач должно приводить к исключению.");
+ "Наложение времени задач должно приводить к исключению.\n"
+ + task.toString());
// изменяем период задачи на перекрвыающий все время выполнения существующей задачи
task.setStartTime(LocalDateTime.now().plusMinutes(10));
task.setDuration(Duration.ofMinutes(50));
- assertThrows(TaskCrossTimeException.class,
+ assertThrows(TimeIntersectionException.class,
() -> {
manager.addNewTask(task);
},
- "Наложение времени задач должно приводить к исключению.");
+ "Наложение времени задач должно приводить к исключению.\n"
+ + task.toString());
}
/**
diff --git a/test/ManagersTest.java b/test/managers/ManagersTest.java
similarity index 96%
rename from test/ManagersTest.java
rename to test/managers/ManagersTest.java
index 7792ab1..c9d1033 100644
--- a/test/ManagersTest.java
+++ b/test/managers/ManagersTest.java
@@ -1,3 +1,5 @@
+package managers;
+
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertNotNull;
diff --git a/test/TaskManagerTest.java b/test/managers/TaskManagerTest.java
similarity index 85%
rename from test/TaskManagerTest.java
rename to test/managers/TaskManagerTest.java
index 1e3651b..1b0bbd2 100644
--- a/test/TaskManagerTest.java
+++ b/test/managers/TaskManagerTest.java
@@ -1,3 +1,6 @@
+package managers;
+
+import exceptions.NotFoundException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import tasks.Epic;
@@ -190,10 +193,17 @@ void removeTask() {
"-",
LocalDateTime.now(),
Duration.ofMinutes(10)));
+
+ assertTrue(!manager.getTaskList().isEmpty(),
+ "Отсутствует задача для удаления.");
+
manager.removeTask(taskId);
- Task task = manager.getTask(taskId);
- assertNull(task, "Задача не удалена.");
+ assertThrows(NotFoundException.class,
+ () -> {
+ manager.getTask(taskId);
+ },
+ "Попытка чтения несуществующей задачи должна приводить к исключению.");
}
@Test
@@ -206,13 +216,21 @@ void removeEpic() {
LocalDateTime.now(),
Duration.ofMinutes(30)));
- manager.removeEpic(epicId);
+ assertTrue(!manager.getEpicList().isEmpty(),
+ "Отсутствует эпик для удаления.");
- Epic epic = manager.getEpic(epicId);
- Subtask subtask = manager.getSubtask(subtaskId);
+ manager.removeEpic(epicId);
- assertNull(epic, "Эпик не удален.");
- assertNull(subtask, "Подзадача удаленного эпика не удалена.");
+ assertThrows(NotFoundException.class,
+ () -> {
+ manager.getEpic(epicId);
+ },
+ "Попытка чтения несуществующго эпика должна приводить к исключению.");
+ assertThrows(NotFoundException.class,
+ () -> {
+ manager.getSubtask(subtaskId);
+ },
+ "Попытка чтения несуществующей подзадачи должна приводить к исключению.");
}
@Test
@@ -225,11 +243,16 @@ void removeSubtask() {
LocalDateTime.now(),
Duration.ofMinutes(30)));
- manager.removeSubtask(subtaskId);
+ assertTrue(!manager.getSubtaskList().isEmpty(),
+ "Отсутствует подзадача для удаления.");
- Subtask subtask = manager.getSubtask(subtaskId);
+ manager.removeSubtask(subtaskId);
- assertNull(subtask, "Подзадача не удалена.");
+ assertThrows(NotFoundException.class,
+ () -> {
+ manager.getSubtask(subtaskId);
+ },
+ "Попытка чтения несуществующей подзадачи должна приводить к исключению.");
}
@Test
@@ -292,9 +315,16 @@ void removeAllTasks() {
manager.addNewTask(new Task("Test removeAllTasks task2",
"2", LocalDateTime.now().plusMinutes(40), Duration.ofMinutes(30)));
+ assertTrue(!manager.getTaskList().isEmpty(),
+ "Отсутствуют задачи для удаления.");
+
manager.removeAllTasks();
- assertTrue(manager.getTaskList().isEmpty(), "Задачи не удалены.");
+ assertThrows(NotFoundException.class,
+ () -> {
+ manager.getTaskList();
+ },
+ "Попытка чтения пустого списка задач должна приводить к исключению.");
}
@Test
@@ -307,11 +337,16 @@ void removeAllEpics() {
"Test removeAllEpics Subtask1",
"1", LocalDateTime.now(), Duration.ofMinutes(30)));
+ assertTrue(!manager.getEpicList().isEmpty(),
+ "Отсутствуют эпики для удаления.");
+
manager.removeAllEpics();
- assertTrue(manager.getEpicList().isEmpty(), "Эпики не удалены.");
- assertTrue(manager.getSubtaskList().isEmpty(),
- "Подзадачи удаленных эпиков не удалены.");
+ assertThrows(NotFoundException.class,
+ () -> {
+ manager.getEpicList();
+ },
+ "Попытка чтения пустого списка эпиков должна приводить к исключению.");
}
@Test
@@ -331,15 +366,23 @@ void removeAllSubtasks() {
"Test removeAllSubtasks Subtask3",
"3", LocalDateTime.now().plusMinutes(80), Duration.ofMinutes(30)));
+ assertTrue(!manager.getSubtaskList().isEmpty(),
+ "Отсутствуют подзадачи для удаления.");
+
manager.removeAllSubtasks();
- assertTrue(manager.getSubtaskList().isEmpty(), "Подзадачи не удалены.");
assertTrue(manager.getEpic(epicId).getSubtasks().isEmpty(),
"не удалены идениификаторы подзадач эпика:\n"
+ manager.getEpic(epicId).toString());
assertTrue(manager.getEpic(epicId2).getSubtasks().isEmpty(),
"не удалены идениификаторы подзадач эпика:\n"
+ manager.getEpic(epicId2).toString());
+
+ assertThrows(NotFoundException.class,
+ () -> {
+ manager.getSubtaskList();
+ },
+ "Попытка чтения пустого списка подзадач должна приводить к исключению.");
}
@Test