diff --git a/.idea/libraries/gson_2_8_2.xml b/.idea/libraries/gson_2_8_2.xml new file mode 100644 index 0000000..4b09acc --- /dev/null +++ b/.idea/libraries/gson_2_8_2.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/csvTaskFile.csv b/csvTaskFile.csv new file mode 100644 index 0000000..97fdc8e --- /dev/null +++ b/csvTaskFile.csv @@ -0,0 +1,5 @@ +id,type,name,status,description,epic +1,Task,1,NEW,Task1 +2,Task,2,NEW,Task2 +3,Epic,3,NEW,Epic1 +4,SubTask,6,NEW,Sub 1,3 diff --git a/java-kanban.iml b/java-kanban.iml index bc0c38b..45d53d1 100644 --- a/java-kanban.iml +++ b/java-kanban.iml @@ -71,5 +71,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/adapters/EpicAdapter.java b/src/adapters/EpicAdapter.java new file mode 100644 index 0000000..b70874e --- /dev/null +++ b/src/adapters/EpicAdapter.java @@ -0,0 +1,45 @@ +package adapters; + +import com.google.gson.*; +import model.Epic; +import model.Status; + +import java.lang.reflect.Type; +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public class EpicAdapter implements JsonSerializer, JsonDeserializer { + + private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"); + + @Override + public JsonElement serialize(Epic task, Type typeOfSrc, JsonSerializationContext context) { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("id", task.getId()); + jsonObject.addProperty("taskName", task.getTaskName()); + jsonObject.addProperty("status", task.getStatus().name()); + jsonObject.addProperty("content", task.getContent()); + jsonObject.addProperty("startTime", task.getStartTime().format(formatter)); + jsonObject.addProperty("duration", task.getDuration().toMinutes()); + jsonObject.addProperty("epicSubs", task.getEpicSubs().toString()); + + return jsonObject; + } + + @Override + public Epic deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + JsonObject jsonObject = json.getAsJsonObject(); + + Integer id = jsonObject.get("id").getAsInt(); + String taskName = jsonObject.get("taskName").getAsString(); + Status status = Status.valueOf(jsonObject.get("status").getAsString()); + String content = jsonObject.get("content").getAsString(); + + LocalDateTime startTime = LocalDateTime.parse(jsonObject.get("startTime").getAsString(), formatter); + + Duration duration = Duration.ofMinutes(jsonObject.get("duration").getAsLong()); + + return new Epic(taskName, content, status, id, startTime, duration); + } +} diff --git a/src/adapters/SubTaskAdapter.java b/src/adapters/SubTaskAdapter.java new file mode 100644 index 0000000..e57aa96 --- /dev/null +++ b/src/adapters/SubTaskAdapter.java @@ -0,0 +1,46 @@ +package adapters; + +import com.google.gson.*; +import model.SubTask; +import model.Status; + +import java.lang.reflect.Type; +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public class SubTaskAdapter implements JsonSerializer, JsonDeserializer { + + private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"); + + @Override + public JsonElement serialize(SubTask task, Type typeOfSrc, JsonSerializationContext context) { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("id", task.getId()); + jsonObject.addProperty("taskName", task.getTaskName()); + jsonObject.addProperty("status", task.getStatus().name()); + jsonObject.addProperty("content", task.getContent()); + jsonObject.addProperty("startTime", task.getStartTime().format(formatter)); + jsonObject.addProperty("duration", task.getDuration().toMinutes()); + jsonObject.addProperty("masterId", task.getMasterId()); + + return jsonObject; + } + + @Override + public SubTask deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + JsonObject jsonObject = json.getAsJsonObject(); + + Integer id = jsonObject.get("id").getAsInt(); + String taskName = jsonObject.get("taskName").getAsString(); + Status status = Status.valueOf(jsonObject.get("status").getAsString()); + String content = jsonObject.get("content").getAsString(); + Integer masterId = jsonObject.get("masterId").getAsInt(); + + LocalDateTime startTime = LocalDateTime.parse(jsonObject.get("startTime").getAsString(), formatter); + + Duration duration = Duration.ofMinutes(jsonObject.get("duration").getAsLong()); + + return new SubTask(taskName, content, status, masterId, id, startTime, duration); + } +} diff --git a/src/adapters/TaskAdapter.java b/src/adapters/TaskAdapter.java new file mode 100644 index 0000000..e07f4e7 --- /dev/null +++ b/src/adapters/TaskAdapter.java @@ -0,0 +1,46 @@ +package adapters; + +import com.google.gson.*; +import model.Task; +import model.Status; + +import java.lang.reflect.Type; +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public class TaskAdapter implements JsonSerializer, JsonDeserializer { + + private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"); + + @Override + public JsonElement serialize(Task task, Type typeOfSrc, JsonSerializationContext context) { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("id", task.getId()); + jsonObject.addProperty("taskName", task.getTaskName()); + jsonObject.addProperty("status", task.getStatus().name()); + jsonObject.addProperty("content", task.getContent()); + + jsonObject.addProperty("startTime", task.getStartTime().format(formatter)); + + jsonObject.addProperty("duration", task.getDuration().toMinutes()); + + return jsonObject; + } + + @Override + public Task deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + JsonObject jsonObject = json.getAsJsonObject(); + + Integer id = jsonObject.get("id").getAsInt(); + String taskName = jsonObject.get("taskName").getAsString(); + Status status = Status.valueOf(jsonObject.get("status").getAsString()); + String content = jsonObject.get("content").getAsString(); + + LocalDateTime startTime = LocalDateTime.parse(jsonObject.get("startTime").getAsString(), formatter); + + Duration duration = Duration.ofMinutes(jsonObject.get("duration").getAsLong()); + + return new Task(taskName, content, status, id, startTime, duration); + } +} diff --git a/src/handlers/EpicHandler.java b/src/handlers/EpicHandler.java new file mode 100644 index 0000000..61c3cc5 --- /dev/null +++ b/src/handlers/EpicHandler.java @@ -0,0 +1,93 @@ +package handlers; + +import adapters.EpicAdapter; +import com.google.gson.GsonBuilder; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import manager.CrossingException; +import manager.FileBackedTaskManager; +import model.Epic; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +public class EpicHandler extends TaskHandler implements HttpHandler { + + + public EpicHandler(FileBackedTaskManager master) { + super(master); + } + + @Override + public void get(HttpExchange exchange) throws IOException { + try { + List tasks = new ArrayList<>(master.getAllEpics()); + String response = gson.toJson(tasks); + sendResponse(exchange, response, 200); + } catch (Exception e) { + e.getMessage(); + } + + } + + @Override + public void post(HttpExchange exchange) throws IOException { + //Запускаем поток чтения тела запроса и создаём из него новый объект task, который отправляем в менеджер. + InputStreamReader isr = new InputStreamReader(exchange.getRequestBody(), StandardCharsets.UTF_8); + Epic task = gson.fromJson(isr, Epic.class); + try { + master.addEpic(task); + String response = "Задача " + task.getId() + " успешно создана"; + sendResponse(exchange, response, 201); + } catch (CrossingException e) { + String response = e.getMessage(); + sendResponse(exchange, response, 406); + } + } + + @Override + public void delete(HttpExchange exchange) throws IOException { + master.eraseEpicHashMap(); + String response = "Все задачи удалены"; + sendResponse(exchange, response, 200); + } + + @Override + public void getId(Integer id, HttpExchange exchange) throws IOException { + try { + Epic task = master.getEpic(id); + String response = gson.toJson(task); + sendResponse(exchange, response, 200); + } catch (Exception e) { + String response = "Такой задачи не существует"; + sendResponse(exchange, response, 404); + } + } + + @Override + public void postId(Integer id, HttpExchange exchange) throws IOException { + InputStreamReader isr = new InputStreamReader(exchange.getRequestBody(), StandardCharsets.UTF_8); + Epic task = gson.fromJson(isr, Epic.class); + task.setId(id); + master.updateEpic(task); + String response = "Задача " + task.getId() + " успешно обновлена"; + sendResponse(exchange, response, 201); + } + + @Override + public void deleteId(Integer id, HttpExchange exchange) throws IOException { + master.removeEpic(id); + String response = "Задача " + id + " удалена"; + sendResponse(exchange, response, 200); + } + + @Override + protected void gsonInitializator() { + GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.registerTypeAdapter(Epic.class, new EpicAdapter()); + this.gson = gsonBuilder.create(); + } +} diff --git a/src/handlers/HistoryHandler.java b/src/handlers/HistoryHandler.java new file mode 100644 index 0000000..b76d740 --- /dev/null +++ b/src/handlers/HistoryHandler.java @@ -0,0 +1,54 @@ +package handlers; + +import com.google.gson.Gson; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import manager.FileBackedTaskManager; +import model.Task; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + + +public class HistoryHandler implements HttpHandler { + + Gson gson; + FileBackedTaskManager master; + + + public HistoryHandler(FileBackedTaskManager master) { + this.master = master; + } + + @Override + public void handle(HttpExchange exchange) throws IOException { + String method = exchange.getRequestMethod(); + if (method.toString().toLowerCase().equals("get")) { + get(exchange); + } else { + String response = "У нас пока нет таких методов"; + sendResponse(exchange, response, 406); + } + } + + public void get(HttpExchange exchange) throws IOException { + List tasks = new ArrayList<>(master.getHistory()); + String response = tasks.toString(); + sendResponse(exchange, response, 200); + } + + + public void sendResponse(HttpExchange httpExchange, String response, int statusCode) throws IOException { + httpExchange.getResponseHeaders().set("Content-Type", "application/json"); + httpExchange.sendResponseHeaders(statusCode, response.getBytes().length); + OutputStream stream = httpExchange.getResponseBody(); + stream.write(response.getBytes()); + stream.close(); + } + + protected void gsonInitializator() { + this.gson = new Gson(); + } +} diff --git a/src/handlers/PriorityHandler.java b/src/handlers/PriorityHandler.java new file mode 100644 index 0000000..931d556 --- /dev/null +++ b/src/handlers/PriorityHandler.java @@ -0,0 +1,48 @@ +package handlers; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import manager.FileBackedTaskManager; +import model.Task; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + + +public class PriorityHandler implements HttpHandler { + + FileBackedTaskManager master; + + public PriorityHandler(FileBackedTaskManager master) { + this.master = master; + } + + @Override + public void handle(HttpExchange exchange) throws IOException { + String method = exchange.getRequestMethod(); + if (method.toString().toLowerCase().equals("get")) { + get(exchange); + } else { + String response = "У нас пока нет таких методов"; + sendResponse(exchange, response, 406); + } + } + + public void get(HttpExchange exchange) throws IOException { + List tasks = new ArrayList<>(master.getPrioritizedTasks()); + String response = tasks.toString(); + sendResponse(exchange, response, 200); + } + + + public void sendResponse(HttpExchange httpExchange, String response, int statusCode) throws IOException { + httpExchange.getResponseHeaders().set("Content-Type", "application/json"); + httpExchange.sendResponseHeaders(statusCode, response.getBytes().length); + OutputStream stream = httpExchange.getResponseBody(); + stream.write(response.getBytes()); + stream.close(); + } + +} diff --git a/src/handlers/SubHandler.java b/src/handlers/SubHandler.java new file mode 100644 index 0000000..4325aae --- /dev/null +++ b/src/handlers/SubHandler.java @@ -0,0 +1,94 @@ +package handlers; + + +import adapters.SubTaskAdapter; +import com.google.gson.GsonBuilder; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import manager.CrossingException; +import manager.FileBackedTaskManager; +import model.SubTask; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +public class SubHandler extends TaskHandler implements HttpHandler { + + + public SubHandler(FileBackedTaskManager master) { + super(master); + } + + @Override + public void get(HttpExchange exchange) throws IOException { + try { + List tasks = new ArrayList<>(master.getAllSubs()); + String response = gson.toJson(tasks); + sendResponse(exchange, response, 200); + } catch (Exception e) { + e.getMessage(); + } + + } + + @Override + public void post(HttpExchange exchange) throws IOException { + //Запускаем поток чтения тела запроса и создаём из него новый объект task, который отправляем в менеджер. + InputStreamReader isr = new InputStreamReader(exchange.getRequestBody(), StandardCharsets.UTF_8); + SubTask task = gson.fromJson(isr, SubTask.class); + try { + master.addSub(task); + String response = "Задача " + task.getId() + " успешно создана"; + sendResponse(exchange, response, 201); + } catch (CrossingException e) { + String response = e.getMessage(); + sendResponse(exchange, response, 406); + } + } + + @Override + public void delete(HttpExchange exchange) throws IOException { + master.eraseSubHashMap(); + String response = "Все подзадачи удалены"; + sendResponse(exchange, response, 200); + } + + @Override + public void getId(Integer id, HttpExchange exchange) throws IOException { + try { + SubTask task = master.getSubtask(id); + String response = gson.toJson(task); + sendResponse(exchange, response, 200); + } catch (Exception e) { + String response = "Такой задачи не существует"; + sendResponse(exchange, response, 404); + } + } + + @Override + public void postId(Integer id, HttpExchange exchange) throws IOException { + InputStreamReader isr = new InputStreamReader(exchange.getRequestBody(), StandardCharsets.UTF_8); + SubTask task = gson.fromJson(isr, SubTask.class); + task.setId(id); + master.updateSubTask(task); + String response = "Задача " + task.getId() + " успешно обновлена"; + sendResponse(exchange, response, 201); + } + + @Override + public void deleteId(Integer id, HttpExchange exchange) throws IOException { + master.removeSubTask(id); + String response = "Задача " + id + " удалена"; + sendResponse(exchange, response, 200); + } + + @Override + protected void gsonInitializator() { + GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.registerTypeAdapter(SubTask.class, new SubTaskAdapter()); + this.gson = gsonBuilder.create(); + } +} diff --git a/src/handlers/TaskHandler.java b/src/handlers/TaskHandler.java new file mode 100644 index 0000000..a60f535 --- /dev/null +++ b/src/handlers/TaskHandler.java @@ -0,0 +1,163 @@ +package handlers; + +import adapters.TaskAdapter; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import manager.CrossingException; +import manager.FileBackedTaskManager; +import model.Task; + +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +import java.io.IOException; + + +public class TaskHandler implements HttpHandler { + + Gson gson; + GsonBuilder gsonBuilder; + FileBackedTaskManager master; + + + public TaskHandler(FileBackedTaskManager master) { + this.master = master; + gsonInitializator(); + } + + @Override + public void handle(HttpExchange exchange) throws IOException { + Integer commandId = -1; + String path = exchange.getRequestURI().getPath(); + String method = exchange.getRequestMethod(); + String[] pathDeplete = path.split("/"); + try { + commandId = Integer.parseInt(pathDeplete[2]); + } catch (Exception e) { + commandId = -1; + } + + if (commandId < 0) { + noIdPath(method, exchange); + + } else { + withIdPath(method, commandId, exchange); + + } + + + } + + public void get(HttpExchange exchange) throws IOException { + List tasks = new ArrayList<>(master.getAllTasks()); + String response = gson.toJson(tasks); + sendResponse(exchange, response, 200); + } + + public void post(HttpExchange exchange) throws IOException { + //Запускаем поток чтения тела запроса и создаём из него новый объект task, который отправляем в менеджер. + InputStreamReader isr = new InputStreamReader(exchange.getRequestBody(), StandardCharsets.UTF_8); + Task task = gson.fromJson(isr, Task.class); + try { + master.addTask(task); + String response = "Задача " + task.getId() + " успешно создана"; + sendResponse(exchange, response, 201); + } catch (CrossingException e) { + String response = e.getMessage(); + sendResponse(exchange, response, 406); + } + //Высылаем ответ клиенту + + } + + public void delete(HttpExchange exchange) throws IOException { + master.eraseTaskHashMap(); + String response = "Все задачи удалены"; + sendResponse(exchange, response, 200); + } + + public void getId(Integer id, HttpExchange exchange) throws IOException { + try { + Task task = master.getTask(id); + String response = gson.toJson(task); + sendResponse(exchange, response, 200); + } catch (Exception e) { + String response = "Такой задачи не существует"; + sendResponse(exchange, response, 404); + } + + } + + public void postId(Integer id, HttpExchange exchange) throws IOException { + InputStreamReader isr = new InputStreamReader(exchange.getRequestBody(), StandardCharsets.UTF_8); + Task task = gson.fromJson(isr, Task.class); + task.setId(id); + master.updateTask(task); + String response = "Задача " + task.getId() + " успешно обновлена"; + sendResponse(exchange, response, 201); + } + + public void deleteId(Integer id, HttpExchange exchange) throws IOException { + master.removeTask(id); + String response = "Задача " + id + " удалена"; + sendResponse(exchange, response, 200); + } + + public void dfM() { + String response = "Неизвестно как, но мы отправили неверный метод"; + System.out.println(response); + } + + public void noIdPath(String method, HttpExchange exchange) throws IOException { + switch (method.toLowerCase()) { + case "get": + get(exchange); + break; + case "post": + post(exchange); + break; + case "delete": + delete(exchange); + break; + default: + dfM(); + break; + } + } + + public void withIdPath(String method, Integer id, HttpExchange exchange) throws IOException { + switch (method.toLowerCase()) { + case "get": + getId(id, exchange); + break; + case "post": + postId(id, exchange); + break; + case "delete": + deleteId(id, exchange); + break; + default: + dfM(); + break; + } + } + + public void sendResponse(HttpExchange httpExchange, String response, int statusCode) throws IOException { + httpExchange.getResponseHeaders().set("Content-Type", "application/json"); + httpExchange.sendResponseHeaders(statusCode, response.getBytes().length); + OutputStream stream = httpExchange.getResponseBody(); + stream.write(response.getBytes()); + stream.close(); + } + + protected void gsonInitializator() { + GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.registerTypeAdapter(Task.class, new TaskAdapter()); + this.gson = gsonBuilder.create(); + } +} diff --git a/src/manager/CrossingException.java b/src/manager/CrossingException.java new file mode 100644 index 0000000..c9cb4a9 --- /dev/null +++ b/src/manager/CrossingException.java @@ -0,0 +1,7 @@ +package manager; + +public class CrossingException extends RuntimeException { + public CrossingException(String message) { + super(message); + } +} diff --git a/src/manager/FileBackedTaskManager.java b/src/manager/FileBackedTaskManager.java new file mode 100644 index 0000000..13163f9 --- /dev/null +++ b/src/manager/FileBackedTaskManager.java @@ -0,0 +1,323 @@ +package manager; + +import model.Epic; +import model.Status; +import model.SubTask; +import model.Task; + +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; + +import static java.lang.Integer.parseInt; + + +public class FileBackedTaskManager extends InMemoryTaskManager { + + //Новые поля + private Path taskFile; + + + //Конструктор для тестов + public FileBackedTaskManager(String test) { + + try { + createTempFile(); + } catch (ManagerSaveException ex) { + System.out.println(ex.getMessage()); + } + } + + + public FileBackedTaskManager() { + this.taskFile = Paths.get("csvTaskFile.csv"); + try { + createFile(); + } catch (ManagerSaveException ex) { + System.out.println(ex.getMessage()); + } + } + + //Начало переписанных методов + @Override + public void addTask(Task task) throws CrossingException { + boolean isCrossed = tasks.values().stream() + .anyMatch(existingTask -> existingTask.isTimeCrossed(task)); + + isCrossed = isCrossed || epics.values().stream() + .anyMatch(existingTask -> existingTask.isTimeCrossed(task)); + + isCrossed = isCrossed || subs.values().stream() + .anyMatch(existingTask -> existingTask.isTimeCrossed(task)); + if (isCrossed) { + throw new CrossingException("На данное время уже назначена задача"); + } else { + taskId++; + tasks.put(taskId, task); + task.setId(taskId); + save(); + } + } + + @Override + public void addEpic(Epic task) throws CrossingException { + boolean isCrossed = tasks.values().stream() + .anyMatch(existingTask -> existingTask.isTimeCrossed(task)); + + isCrossed = isCrossed || epics.values().stream() + .anyMatch(existingTask -> existingTask.isTimeCrossed(task)); + + isCrossed = isCrossed || subs.values().stream() + .anyMatch(existingTask -> existingTask.isTimeCrossed(task)); + if (isCrossed) { + throw new CrossingException("На данное время уже назначена задача"); + } else { + taskId++; + epics.put(taskId, task); + task.setId(taskId); + save(); + } + } + + @Override + public void addSub(SubTask task) throws CrossingException { + boolean isCrossed = tasks.values().stream() + .anyMatch(existingTask -> existingTask.isTimeCrossed(task)); + + isCrossed = isCrossed || epics.values().stream() + .filter(entry -> !entry.getId().equals(task.getMasterId())) + .anyMatch(existingTask -> existingTask.isTimeCrossed(task)); + + isCrossed = isCrossed || subs.values().stream() + .anyMatch(existingTask -> existingTask.isTimeCrossed(task)); + if (isCrossed) { + throw new CrossingException("На данное время уже назначена задача"); + } else { + taskId++; + subs.put(taskId, task); + task.setId(taskId); + epics.get(task.getMasterId()).addSubTask(task); + epics.get(task.getMasterId()).statusUpdate(); + save(); + } + } + + //Удаление по идентификатору + @Override + public void removeTask(Integer id) { + tasks.remove(id); + save(); + } + + //Удаление всех задач + @Override + public void eraseTaskHashMap() { + tasks.clear(); + save(); + } + + //Обновление задачи + @Override + public void updateTask(Task task) { + tasks.put(task.getId(), task); + save(); + } + + //Удаление всех задач + @Override + public void eraseEpicHashMap() { + eraseSubHashMap(); + epics.clear(); + save(); + } + + //Обновление задачи + @Override + public void updateEpic(Epic task) { + epics.put(task.getId(), task); + save(); + } + + //Удаление по идентификатору + @Override + public void removeEpic(Integer id) { + epics.get(id).getEpicSubs().keySet().forEach(subs::remove); + epics.remove(id); + save(); + } + + //Удаление всех подзадач (без удаления эпиков. Эпики выставляются в статус NEW, так как подзадач нет.) + @Override + public void eraseSubHashMap() { + subs.clear(); + epics.values().forEach(epic -> { + epic.clearSub(); + epic.statusUpdate(); + }); + save(); + } + + //Обновление задачи + @Override + public void updateSubTask(SubTask task) { + subs.put(task.getId(), task); + epics.get(task.getMasterId()).addSubTask(task); + epics.get(task.getMasterId()).statusUpdate(); + save(); + } + + //Удаление по идентификатору + @Override + public void removeSubTask(Integer id) { + subs.remove(id); + epics.values().forEach(epic -> { + if (epic.getEpicSubs().containsKey(id)) { + epic.getEpicSubs().remove(id); + epic.statusUpdate(); + } + }); + save(); + } + + //ДОПОЛНИТЕЛЬНЫЕ ОПЕРАЦИОННЫЕ МЕТОДЫ + //Метод автосохранения. Содержимое мапы uniMap переносится в файл CSV. И наполняется TreeSet + private void save() { + HashMap uniMap = createUniMap(); + timeSortedTasks.clear(); + StringBuilder sb = new StringBuilder("id,type,name,status,description,epic\n"); + for (int i = 1; i <= taskId; i++) { + if (uniMap.containsKey(i)) { + sb.append(lineFormater(uniMap.get(i)) + "\n"); + timeSortedTasks.add(uniMap.get(i)); + } + } + try (BufferedWriter writer = new BufferedWriter(new FileWriter(String.valueOf(taskFile)))) { + writer.write(String.valueOf(sb)); + } catch (IOException e) { + System.out.println("IOI save exception"); + } + } + + //Метод формирует хэш-мапу для автосохранения в файл + private HashMap createUniMap() { + HashMap uniMap = new HashMap<>(); + for (int i = 1; i <= taskId; i++) { + if (tasks.containsKey(i)) { + uniMap.put(i, tasks.get(i)); + } else if (epics.containsKey(i)) { + uniMap.put(i, epics.get(i)); + } else if (subs.containsKey(i)) { + uniMap.put(i, subs.get(i)); + } + } + return uniMap; + } + + //Метод формирует линию для записи формата id,type,name,status,description,epic + private String lineFormater(Task task) { + + if (task instanceof SubTask) { + SubTask subTask = (SubTask) task; + + return subTask.getId() + "," + getTaskType(task) + "," + subTask.getTaskName() + "," + subTask.getStatus() + "," + subTask.getContent() + "," + subTask.getMasterId(); + } + return task.getId() + "," + getTaskType(task) + "," + task.getTaskName() + "," + task.getStatus() + "," + task.getContent(); + } + + //Метод определяет тип задачи и возвращает в виде строки + private String getTaskType(Task task) { + Class o = task.getClass(); + return o.getSimpleName(); + } + + //Метод инициализирует содержимое CSV файла в память программы + private void loadFromFile() { + ArrayList data = new ArrayList<>(); + try { + data = (ArrayList) Files.readAllLines(taskFile); + } catch (IOException e) { + System.out.println("Ошибка при чтении из файла"); + } + data.removeFirst(); + assert data != null; + for (String line : data) { + separateLines(line); + } + + } + + //Вспомогателльный метод readFromFile. Метод бьёт на строки id,type,name,status,description,epic + // 0 - ID, 1 - TYPE, 2 - NAME, 3 - STATUS, 4 - DESCRIPTION, 5 - EPIC, 6 - startTime, 7 - Duration + private void separateLines(String initialString) { + String[] lines = initialString.split(","); + int resId = parseInt(lines[0]); + String resType = lines[1]; + String resTaskName = lines[2]; + Status resTaskStatus = Status.valueOf(lines[3]); + String resContent = lines[4]; + int resEpicNo = 0; + if (resType.equals("SubTask")) resEpicNo = parseInt(lines[5]); + switch (resType) { + case "Task": + Task task = new Task(resTaskName, resContent, resTaskStatus); + taskId = resId - 1; + addTask(task); + task.setId(resId); + taskId = resId; + break; + case "Epic": + Epic epic = new Epic(resTaskName, resContent, resTaskStatus); + taskId = resId - 1; + addEpic(epic); + epic.setId(resId); + taskId = resId; + break; + case "SubTask": + SubTask subTask = new SubTask(resTaskName, resContent, resTaskStatus, resEpicNo); + taskId = resId - 1; + addSub(subTask); + subTask.setId(resId); + taskId = resId; + break; + } + } + + private void eraseFile() { + try { + Files.newBufferedWriter(taskFile).close(); + } catch (IOException e) { + System.out.println("Ошибка при удалении данных"); + } + + } + + private void createTempFile() throws ManagerSaveException { + try { + taskFile = Files.createTempFile("testFile", ".csv"); + taskFile.toFile().deleteOnExit(); + } catch (IOException ex) { + throw new ManagerSaveException("Ошибка при создании временного файла"); + } + } + + private void createFile() throws ManagerSaveException { + + try { + if (!Files.exists(taskFile)) { + Files.createFile(taskFile); + } + } catch (IOException ex) { + throw new ManagerSaveException("Ошибка при создании постоянного CSV файла"); + } + } + + public Path getTaskFile() { + return taskFile; + } + +} diff --git a/src/manager/HttpTaskServer.java b/src/manager/HttpTaskServer.java new file mode 100644 index 0000000..c610d2d --- /dev/null +++ b/src/manager/HttpTaskServer.java @@ -0,0 +1,63 @@ +package manager; + +import com.sun.net.httpserver.HttpServer; +import handlers.*; +import model.Epic; +import model.Status; +import model.SubTask; +import model.Task; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.time.Duration; +import java.time.LocalDateTime; + +public class HttpTaskServer { + + private HttpServer server; + private final int applicationPort = 8080; + FileBackedTaskManager master = new FileBackedTaskManager(); + + public HttpTaskServer() throws IOException { + this.server = HttpServer.create(new InetSocketAddress(applicationPort), 0); + } + + public void startServer() { + server.createContext("/tasks", new TaskHandler(master)); + server.createContext("/epics", new EpicHandler(master)); + server.createContext("/subtasks", new SubHandler(master)); + server.createContext("/history", new HistoryHandler(master)); + server.createContext("/prioritized", new PriorityHandler(master)); + server.start(); + System.out.println("Сервер запущен на порту: " + applicationPort); + } + + public void stopServer() { + server.stop(10); + System.out.println("Сервер остановлен"); + } + + public void test() { + Task task1 = new Task("1", "Task1", Status.NEW); + Task task2 = new Task("2", "Task2", Status.NEW); + Epic epic1 = new Epic("3", "Epic1", Status.NEW); + SubTask sub1 = new SubTask("6", "Sub 1", Status.NEW, 3); + task1.setStartTime(LocalDateTime.of(2000, 1, 1, 0, 0)); + task1.setDuration(Duration.ofMinutes(10)); + task2.setStartTime(LocalDateTime.of(2000, 1, 1, 0, 10)); + epic1.setDuration(Duration.ofMinutes(10)); + epic1.setStartTime(LocalDateTime.of(1999, 1, 1, 0, 0)); + task2.setDuration(Duration.ofMinutes(10)); + sub1.setStartTime(LocalDateTime.of(1970, 1, 1, 0, 0)); + sub1.setDuration(Duration.ofMinutes(10)); + master.addTask(task1); + master.addTask(task2); + master.addEpic(epic1); + master.addSub(sub1); + } + + public FileBackedTaskManager getMaster() { + return master; + } + +} diff --git a/src/manager/InMemoryTaskManager.java b/src/manager/InMemoryTaskManager.java index b2904c5..580a9fc 100644 --- a/src/manager/InMemoryTaskManager.java +++ b/src/manager/InMemoryTaskManager.java @@ -4,18 +4,15 @@ import model.SubTask; import model.Task; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; +import java.util.*; public class InMemoryTaskManager implements TaskManager { - //Хранение всех типов - private Integer taskId = 0; - - private final HashMap tasks = new HashMap<>(); - private final HashMap epics = new HashMap<>(); - private final HashMap subs = new HashMap<>(); + protected Integer taskId = 0; + protected TreeSet timeSortedTasks = new TreeSet<>(); + protected final HashMap tasks = new HashMap<>(); + protected final HashMap epics = new HashMap<>(); + protected final HashMap subs = new HashMap<>(); public HistoryManager historian = new InMemoryHistoryManager(); @@ -25,7 +22,6 @@ public Collection getAllTasks() { return tasks.values(); } - //Получение по идентификатору @Override public Task getTask(Integer id) { historian.add(tasks.get(id)); @@ -40,10 +36,23 @@ public void eraseTaskHashMap() { //Создание задачи @Override - public void addTask(Task task) { - taskId++; - tasks.put(taskId, task); - task.setId(taskId); + public void addTask(Task task) throws CrossingException { + boolean isCrossed = tasks.values().stream() + .anyMatch(existingTask -> existingTask.isTimeCrossed(task)); + + isCrossed = isCrossed || epics.values().stream() + .anyMatch(existingTask -> existingTask.isTimeCrossed(task)); + + isCrossed = isCrossed || subs.values().stream() + .anyMatch(existingTask -> existingTask.isTimeCrossed(task)); + if (isCrossed) { + throw new CrossingException("На данное время уже назначена задача"); + } else { + taskId++; + tasks.put(taskId, task); + task.setId(taskId); + timeSortedTasks.add(task); + } } //Обновление задачи @@ -82,10 +91,23 @@ public void eraseEpicHashMap() { //Создание задачи @Override - public void addEpic(Epic task) { - taskId++; - epics.put(taskId, task); - task.setId(taskId); + public void addEpic(Epic task) throws CrossingException { + boolean isCrossed = tasks.values().stream() + .anyMatch(existingTask -> existingTask.isTimeCrossed(task)); + + isCrossed = isCrossed || epics.values().stream() + .anyMatch(existingTask -> existingTask.isTimeCrossed(task)); + + isCrossed = isCrossed || subs.values().stream() + .anyMatch(existingTask -> existingTask.isTimeCrossed(task)); + if (isCrossed) { + throw new CrossingException("На данное время уже назначена задача"); + } else { + taskId++; + epics.put(taskId, task); + task.setId(taskId); + timeSortedTasks.add(task); + } } //Обновление задачи @@ -129,12 +151,26 @@ public void eraseSubHashMap() { //Создание задачи, добавление к существующей model.Epic @Override - public void addSub(SubTask task) { - taskId++; - subs.put(taskId, task); - task.setId(taskId); - epics.get(task.getMasterId()).addSubTask(task); - epics.get(task.getMasterId()).statusUpdate(); + public void addSub(SubTask task) throws CrossingException { + boolean isCrossed = tasks.values().stream() + .anyMatch(existingTask -> existingTask.isTimeCrossed(task)); + + isCrossed = isCrossed || epics.values().stream() + .filter(entry -> !entry.getId().equals(task.getMasterId())) + .anyMatch(existingTask -> existingTask.isTimeCrossed(task)); + + isCrossed = isCrossed || subs.values().stream() + .anyMatch(existingTask -> existingTask.isTimeCrossed(task)); + if (isCrossed) { + throw new CrossingException("На данное время уже назначена задача"); + } else { + taskId++; + subs.put(taskId, task); + task.setId(taskId); + epics.get(task.getMasterId()).addSubTask(task); + epics.get(task.getMasterId()).statusUpdate(); + timeSortedTasks.add(task); + } } //Обновление задачи @@ -163,5 +199,9 @@ public ArrayList getHistory() { return historian.getHistory(); } + @Override + public List getPrioritizedTasks() { + return new ArrayList<>(timeSortedTasks); + } } diff --git a/src/manager/ManagerSaveException.java b/src/manager/ManagerSaveException.java new file mode 100644 index 0000000..c213c23 --- /dev/null +++ b/src/manager/ManagerSaveException.java @@ -0,0 +1,7 @@ +package manager; + +public class ManagerSaveException extends RuntimeException { + public ManagerSaveException(String message) { + super(message); + } +} diff --git a/src/manager/Managers.java b/src/manager/Managers.java index e7cfae5..09de30e 100644 --- a/src/manager/Managers.java +++ b/src/manager/Managers.java @@ -1,8 +1,9 @@ package manager; public class Managers { + //SP7 - класс изменён c InMemoryTaskManager на FileBackedTaskManager public static TaskManager getDefault() { - return new InMemoryTaskManager(); + return new FileBackedTaskManager(); } public static HistoryManager getDefaultHistory() { diff --git a/src/manager/TaskManager.java b/src/manager/TaskManager.java index 65879d1..2ccdd36 100644 --- a/src/manager/TaskManager.java +++ b/src/manager/TaskManager.java @@ -3,9 +3,9 @@ import model.Epic; import model.SubTask; import model.Task; - import java.util.ArrayList; import java.util.Collection; +import java.util.List; public interface TaskManager { @@ -47,4 +47,6 @@ public interface TaskManager { public ArrayList getHistory(); + public List getPrioritizedTasks(); + } diff --git a/src/model/Epic.java b/src/model/Epic.java index 0508d15..59b194a 100644 --- a/src/model/Epic.java +++ b/src/model/Epic.java @@ -1,5 +1,8 @@ package model; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.Comparator; import java.util.HashMap; public class Epic extends Task { @@ -9,8 +12,28 @@ public Epic(String taskName, String content, Status status) { super(taskName, content, status); } + public Epic(String taskName, String content, Status status, Integer id, LocalDateTime startTime, Duration duration) { + super(taskName, content, status, id, startTime, duration); + } + public void addSubTask(SubTask subTask) { epicSubs.put(subTask.getId(), subTask); + refreshTimeLimits(); + } + + private void refreshTimeLimits() { + LocalDateTime endTime; + Task firstTask = epicSubs.values() + .stream() + .min(Comparator.comparing(Task::getStartTime)) + .orElse(null); + Task lastTask = epicSubs.values() + .stream() + .max(Comparator.comparing(Task::getStartTime)) + .orElse(null); + startTime = firstTask.getStartTime(); + endTime = lastTask.getEndTime(); + duration = Duration.between(startTime,endTime); } void printAllEpicSubTasks() { diff --git a/src/model/SubTask.java b/src/model/SubTask.java index f17f3a4..1adf984 100644 --- a/src/model/SubTask.java +++ b/src/model/SubTask.java @@ -1,16 +1,26 @@ package model; +import java.time.Duration; +import java.time.LocalDateTime; import java.util.ArrayList; public class SubTask extends Task { private final Integer masterId; - ArrayList epicAssign = new ArrayList<>(); + public ArrayList epicAssign = new ArrayList<>(); public SubTask(String taskName, String content, Status status, Integer masterId) { super(taskName, content, status); this.masterId = masterId; } + public SubTask(String taskName, String content, Status status, Integer masterId, Integer id, LocalDateTime startTime, Duration duration) { + super(taskName, content, status); + this.masterId = masterId; + setId(id); + setStartTime(startTime); + setDuration(duration); + } + public Integer getMasterId() { return masterId; } diff --git a/src/model/Task.java b/src/model/Task.java index 0fefffc..2f192e5 100644 --- a/src/model/Task.java +++ b/src/model/Task.java @@ -1,21 +1,56 @@ package model; +import java.time.Duration; +import java.time.LocalDateTime; import java.util.Objects; -public class Task { +public class Task implements Comparable { private Integer id;//id задачи private String taskName; // имя задачи private Status status; // статус задачи private String content; // содержимое задачи - - //Конструктор + protected LocalDateTime startTime; + protected Duration duration; public Task(String taskName, String content, Status status) { this.status = status; this.taskName = taskName; this.content = content; + } + + public Task(String taskName, String content, Status status, Integer id, LocalDateTime startTime, Duration duration) { + this.status = status; + this.taskName = taskName; + this.content = content; + this.id = id; + this.startTime = startTime; + this.duration = duration; + } + + public LocalDateTime getEndTime() { + if (startTime != null && duration != null) { + return startTime.plus(duration); + } else { + return LocalDateTime.MIN; + } + } + + public Duration getDuration() { + if (duration != null) { + return duration; + } else { + return Duration.ofMinutes(0); + } + } + + public LocalDateTime getStartTime() { + if (startTime != null) { + return startTime; + } else { + return LocalDateTime.MIN; + } } public Integer getId() { @@ -72,4 +107,31 @@ public String toString() { ", content='" + content + '\'' + '}'; } + + @Override + public int compareTo(Task o) { + if (this.startTime == null && o.startTime == null) { + return 0; + } + if (this.startTime == null) { + return -1; + } + if (o.startTime == null) { + return 1; + } + return this.startTime.compareTo(o.startTime); + } + + public boolean isTimeCrossed(Task task) { + return task.getStartTime().isBefore(this.getEndTime()) && task.getEndTime().isAfter(this.getStartTime()); + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public void setDuration(Duration duration) { + this.duration = duration; + } + } diff --git a/test/FileBackedTaskManagerTest.java b/test/FileBackedTaskManagerTest.java new file mode 100644 index 0000000..8840777 --- /dev/null +++ b/test/FileBackedTaskManagerTest.java @@ -0,0 +1,75 @@ +import manager.FileBackedTaskManager; +import manager.HistoryManager; +import manager.Managers; +import model.Epic; +import model.Status; +import model.SubTask; +import model.Task; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import java.io.IOException; +import java.nio.file.Files; +import java.util.ArrayList; + +public class FileBackedTaskManagerTest { + + private static FileBackedTaskManager master; + private static HistoryManager historian; + private static Task task1; + private static Task task2; + private static Epic epic1; + private static SubTask sub1; + + @BeforeEach + void managersCreationUtilityTest() { + master = new FileBackedTaskManager("true"); + historian = Managers.getDefaultHistory(); + task1 = new Task("1", "Task1", Status.NEW); + task2 = new Task("2", "Task2", Status.NEW); + epic1 = new Epic("3", "Epic1", Status.NEW); + sub1 = new SubTask("6", "Sub 1", Status.NEW, 3); + } + + @Test + void checkFileReadAndWriteProcess() { + master.addTask(task1); + Assertions.assertEquals("1", master.getTask(1).getTaskName()); + Assertions.assertEquals("Task1", master.getTask(1).getContent()); + Assertions.assertEquals(Status.NEW, master.getTask(1).getStatus()); + ArrayList data = new ArrayList<>(); + + try { + data = (ArrayList) Files.readAllLines(master.getTaskFile()); + } catch (IOException e) { + System.out.println("Ошибка при чтении из файла"); + } + Assertions.assertEquals("1,Task,1,NEW,Task1", data.get(1)); + Assertions.assertNotEquals("Task,1,NEW,Task1", data.get(1)); + } + + @Test + void checkFileReadAndWriteProcessMore() { + master.addTask(task1); + master.addTask(task2); + master.addEpic(epic1); + master.addSub(sub1); + Assertions.assertEquals("1", master.getTask(1).getTaskName()); + Assertions.assertEquals("Task1", master.getTask(1).getContent()); + Assertions.assertEquals(Status.NEW, master.getTask(1).getStatus()); + ArrayList data = new ArrayList<>(); + master.removeTask(1); + task2 = new Task("2", "Task2", Status.DONE); + task2.setId(2); + master.updateTask(task2); + + try { + data = (ArrayList) Files.readAllLines(master.getTaskFile()); + } catch (IOException e) { + System.out.println("Ошибка при чтении из файла"); + } + Assertions.assertEquals("2,Task,2,DONE,Task2", data.get(1)); + Assertions.assertNotEquals("Task,1,NEW,Task1", data.get(1)); + } + +} diff --git a/test/HttpServerTest.java b/test/HttpServerTest.java new file mode 100644 index 0000000..6e33e0e --- /dev/null +++ b/test/HttpServerTest.java @@ -0,0 +1,154 @@ +import manager.*; +import model.Epic; +import model.Status; +import model.SubTask; +import model.Task; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +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.nio.charset.StandardCharsets; +import java.time.Duration; +import java.time.LocalDateTime; + +import static org.junit.Assert.assertEquals; + +class HttpServerTest { + + private HttpTaskServer server; + private static Task task1; + private static Task task2; + private static Epic epic1; + private static SubTask sub1; + private static SubTask sub2; + private static SubTask sub3; + private static SubTask sub4; + private static Epic epic2; + private static SubTask sub5; + private static SubTask sub6; + private static SubTask sub7; + private static SubTask sub8; + private static Epic epic3; + + @BeforeEach + void managersCreationUtilityTest() throws IOException { + server = new HttpTaskServer(); + server.startServer(); + task1 = new Task("1", "Task1", Status.NEW); + task2 = new Task("2", "Task2", Status.NEW); + epic1 = new Epic("3", "Epic1", Status.NEW); + sub1 = new SubTask("6", "Sub 1", Status.NEW, 3); + task1.setStartTime(LocalDateTime.of(2000, 1, 1, 0, 0)); + task1.setDuration(Duration.ofMinutes(10)); + task2.setStartTime(LocalDateTime.of(2000, 1, 1, 0, 10)); + epic1.setDuration(Duration.ofMinutes(10)); + epic1.setStartTime(LocalDateTime.of(1999, 1, 1, 0, 0)); + task2.setDuration(Duration.ofMinutes(10)); + sub1.setStartTime(LocalDateTime.of(1970, 1, 1, 0, 0)); + sub1.setDuration(Duration.ofMinutes(10)); + server.getMaster().addTask(task1); + server.getMaster().addTask(task2); + server.getMaster().addEpic(epic1); + server.getMaster().addSub(sub1); + } + + @AfterEach + public void shutDown() { + server.stopServer(); + } + + @Test + void testGetAllTasksEpicsSubs() throws IOException, InterruptedException { + 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()); + Assertions.assertEquals("[{\"id\":1,\"taskName\":\"1\",\"status\":\"NEW\",\"content\":\"Task1\",\"startTime\":\"2000-01-01T00:00:00\",\"duration\":10},{\"id\":2,\"taskName\":\"2\",\"status\":\"NEW\",\"content\":\"Task2\",\"startTime\":\"2000-01-01T00:10:00\",\"duration\":10}]", response.body()); + url = URI.create("http://localhost:8080/epics"); + request = HttpRequest.newBuilder().uri(url).GET().build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + url = URI.create("http://localhost:8080/subtasks"); + request = HttpRequest.newBuilder().uri(url).GET().build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + } + + @Test + void deletingTestForAllTypes() throws IOException, InterruptedException { + HttpClient client = HttpClient.newHttpClient(); + URI url = URI.create("http://localhost:8080/tasks/1"); + HttpRequest request = HttpRequest.newBuilder().uri(url).DELETE().build(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + Assertions.assertEquals("Задача 1 удалена", response.body()); + Assertions.assertEquals(1, server.getMaster().getAllTasks().size()); + url = URI.create("http://localhost:8080/tasks"); + request = HttpRequest.newBuilder().uri(url).DELETE().build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + Assertions.assertEquals("Все задачи удалены", response.body()); + url = URI.create("http://localhost:8080/epics"); + request = HttpRequest.newBuilder().uri(url).DELETE().build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + url = URI.create("http://localhost:8080/subtasks"); + request = HttpRequest.newBuilder().uri(url).DELETE().build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + Assertions.assertEquals(0, server.getMaster().getAllTasks().size()); + Assertions.assertEquals(0, server.getMaster().getAllEpics().size()); + Assertions.assertEquals(0, server.getMaster().getAllSubs().size()); + } + + @Test + void notFoundTest() throws IOException, InterruptedException { + HttpClient client = HttpClient.newHttpClient(); + URI url = URI.create("http://localhost:8080/tasks/5"); + HttpRequest request = HttpRequest.newBuilder().uri(url).GET().build(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(404, response.statusCode()); + } + + @Test + void testPostUpdateMethod () throws IOException, InterruptedException { + String inputJsonTask = "{" + + "\"id\": 1," + + "\"taskName\": \"Updated\"," + + "\"status\": \"NEW\"," + + "\"content\": \"Updated task content.\"," + + "\"startTime\": \"2000-01-01T00:00:00\"," + + "\"duration\": 10" + + "}"; + HttpClient client = HttpClient.newHttpClient(); + URI url = URI.create("http://localhost:8080/tasks/1"); + HttpRequest request = HttpRequest.newBuilder().uri(url).POST(HttpRequest.BodyPublishers.ofString(inputJsonTask, StandardCharsets.UTF_8)).build(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(201, response.statusCode()); + } + + @Test + void testPostFailedTimeCrossingAddingMethod () throws IOException, InterruptedException { + String inputJsonTask = "{" + + "\"id\": 4," + + "\"taskName\": \"Updated\"," + + "\"status\": \"NEW\"," + + "\"content\": \"Updated task content.\"," + + "\"startTime\": \"2000-01-01T00:00:00\"," + + "\"duration\": 10" + + "}"; + HttpClient client = HttpClient.newHttpClient(); + URI url = URI.create("http://localhost:8080/tasks"); + HttpRequest request = HttpRequest.newBuilder().uri(url).POST(HttpRequest.BodyPublishers.ofString(inputJsonTask, StandardCharsets.UTF_8)).build(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(406, response.statusCode()); + } + +} \ No newline at end of file diff --git a/test/InMemoryTaskManagerTest.java b/test/InMemoryTaskManagerTest.java index 3627204..e13ca06 100644 --- a/test/InMemoryTaskManagerTest.java +++ b/test/InMemoryTaskManagerTest.java @@ -6,10 +6,8 @@ import model.SubTask; import model.Task; import org.junit.jupiter.api.Assertions; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; - import java.util.ArrayList; class InMemoryTaskManagerTest { diff --git a/test/OtherInterfacesTestSprint8.java b/test/OtherInterfacesTestSprint8.java new file mode 100644 index 0000000..1638478 --- /dev/null +++ b/test/OtherInterfacesTestSprint8.java @@ -0,0 +1,117 @@ +import manager.CrossingException; +import manager.FileBackedTaskManager; +import manager.HistoryManager; +import manager.Managers; +import model.Epic; +import model.Status; +import model.SubTask; +import model.Task; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import java.time.Duration; +import java.time.LocalDateTime; + +public class OtherInterfacesTestSprint8 { + + private static FileBackedTaskManager master; + private static HistoryManager historian; + private static Task task1; + private static Task task2; + private static Epic epic1; + private static SubTask sub1; + private static SubTask sub2; + private static SubTask sub3; + + @BeforeEach + void managersCreationUtilityTest() { + master = new FileBackedTaskManager("true"); + historian = Managers.getDefaultHistory(); + task1 = new Task("1", "Task1", Status.NEW); + task2 = new Task("2", "Task2", Status.NEW); + epic1 = new Epic("3", "Epic1", Status.NEW); + sub1 = new SubTask("6", "Sub1", Status.NEW, 3); + sub2 = new SubTask("7", "Sub2", Status.NEW, 3); + sub3 = new SubTask("8", "Sub3", Status.NEW, 3); + } + + @Test + void checkEpicStatusChanging() { + master.addTask(task1); + master.addTask(task2); + master.addEpic(epic1); + master.addSub(sub1); + Assertions.assertEquals(Status.NEW, master.getEpic(3).getStatus()); + sub2.setStatus(Status.IN_PROGRESS); + master.addSub(sub2); + master.updateSubTask(new SubTask("7", "Sub2", Status.IN_PROGRESS, 3)); + Assertions.assertEquals(Status.IN_PROGRESS, master.getEpic(3).getStatus()); + master.addSub(sub3); + master.updateSubTask(new SubTask("6", "Sub1", Status.DONE, 3)); + master.updateSubTask(new SubTask("7", "Sub2", Status.DONE, 3)); + master.updateSubTask(new SubTask("8", "Sub3", Status.DONE, 3)); + Assertions.assertEquals(Status.DONE, master.getEpic(3).getStatus()); + } + + @Test + void checkTimeManagerPriority() { + task1.setStartTime(LocalDateTime.of(2002, 1, 1, 0, 10)); + task1.setDuration(Duration.ofMinutes(10)); + task2.setStartTime(LocalDateTime.of(2000, 1, 1, 0, 0)); + task2.setDuration(Duration.ofMinutes(10)); + epic1.setDuration(Duration.ofMinutes(10)); + epic1.setStartTime(LocalDateTime.of(1990, 1, 1, 0, 0)); + master.addTask(task2); + master.addTask(task1); + master.addEpic(epic1); + Assertions.assertEquals(master.getEpic(3), master.getPrioritizedTasks().get(0)); + Assertions.assertEquals(master.getTask(2), master.getPrioritizedTasks().get(2)); + Assertions.assertEquals(master.getTask(1), master.getPrioritizedTasks().get(1)); + } + + @Test + void checkCrossTimeTest() { + task1.setStartTime(LocalDateTime.of(2000, 1, 1, 0, 10)); + task1.setDuration(Duration.ofMinutes(10)); + task2.setStartTime(LocalDateTime.of(2000, 1, 1, 0, 10)); + task2.setDuration(Duration.ofMinutes(10)); + master.addTask(task1); + try { + master.addTask(task2); + } catch (CrossingException e){ + System.out.println(e.getMessage()); + } + task2.setStartTime(LocalDateTime.of(2000, 1, 1, 0, 1)); + task2.setDuration(Duration.ofMinutes(10)); + try{ + master.addTask(task2); + }catch (CrossingException e){ + System.out.println(e.getMessage()); + } + task2.setStartTime(LocalDateTime.of(2000, 1, 1, 0, 19)); + task2.setDuration(Duration.ofMinutes(10)); + try{ + master.addTask(task2); + }catch (CrossingException e){ + System.out.println(e.getMessage()); + } + Assertions.assertEquals(1, master.getAllTasks().size()); + task2.setStartTime(LocalDateTime.of(2000, 1, 1, 0, 20)); + task2.setDuration(Duration.ofMinutes(10)); + master.addTask(task2); + Assertions.assertEquals(2, master.getAllTasks().size()); + } + + void checkEpicTimeUpdate() { + master.addTask(task1); + master.addTask(task2); + epic1.setStartTime(LocalDateTime.of(2000, 1, 1, 0, 10)); + epic1.setDuration(Duration.ofMinutes(10)); + master.addEpic(epic1); + Assertions.assertEquals(LocalDateTime.of(2000, 1, 1, 0, 10), epic1.getStartTime()); + sub1.setStartTime(LocalDateTime.of(2000, 1, 1, 0, 0)); + sub1.setDuration(Duration.ofMinutes(60)); + Assertions.assertEquals(LocalDateTime.of(2000, 1, 1, 0, 0), epic1.getStartTime()); + Assertions.assertEquals(LocalDateTime.of(2000, 1, 1, 0, 60), epic1.getEndTime()); + } +}